バックエンド応答の最適化:キュー、非同期、バックプレッシャー
1)理由: 目標とSLO
目標は、バースト下でも安定した高速応答です。ビジネスはこのSLOを表現します:- API (CRUD/ディレクトリ): p95 ≤ 250-400 ms、エラー率<1%。
- 支払い/決済(非同期):確認のための内部SLA ≤ 2-5分、およびクライアント-インスタント202/Accepted+ステータスポーラー/webhook。
- WS/リアルタイム: RTT p95 ≤ 120ミリ、切断≤ 0。5%.
キー:キューと有能な負荷制限を介してユーザーの応答から「遅い」ステップ(プロバイダ、データベース、外部API)を解除します。
2)基本的な写真: レイテンシーが撮影される場所
ボトルネック:データベース(プール/インデックス)、外部プロバイダ(PSP/ゲーム)、 ブロッキングI/O、 GC/ストップワールド、 JSONシリアル化「、重い」集計。
症状:p99の成長、DB接続キュー、リトレイバースト、再試行嵐。
Antidote:非同期パイプライン+backpressure+timeouts/retreats+idempotency。
3)非同期パターン: SEDAおよびCQRS
SEDA (staged event-driven architecture):処理を段階(ingress→validation→write→integration→notification)に分割します。それぞれに独自のターンと並行限度があります。
CQRS:読み取りと書き込みを分離します。書き込み-ログ/データベースへ、読み取り-投影/キャッシュから。
Outbox:イベントはレコードと一緒に原子的に公開されます(「失われた」メッセージは避けてください)。
佐賀:グローバルな取引の代わりに取引を補償する長いビジネスプロセス。
4)キューとストリーム: 選択とチューニング
RabbitMQ/NATS JetStream-タスクコマンド(ワークキュー)、Kafka-リプレイ付きのイベント/ストリーム。
応答に影響する設定:- Prefetch/max in-flight:データベース/外部APIを"詰まらせないように、ワーカーごとに同時に処理されるメッセージの数(例えば、16-64)を制限します。
- Acker/repeats: idempotent録音の後の'ack';指数遅延とジッタの繰り返しです。
- DLQ/駐車場:無限の後退はありません-Nの試みの後、デッドレターキューに行きます。
- パーティショニング(Kafka):オーダーのための本質によるキー(userId/txnId);パーティーの数を通じて並列化。
5)背圧-溺れない方法
アイデア:SLOのレイテンシー内で処理できるだけ多くを取ります。
技術者:- 入場管理:データベース、PSP、ゲームプロバイダの外部依存関係ごとに競争を制限(セマフォー/ワーカープール)。
- トラフィックシェーピング:サービス入り口と重要なルートでのトークンバケット/リーキーバケット。
- 上の境界線を持つキュー:いっぱいになると、尾(429/503+Retry-After)を切るか、asap-batchに転送します。
- 適応的並行性(AIMD):成功時の並列性の向上、タイムアウト時の減少。
- サーキットブレーカ:外部APIのエラー/タイムアウトによる'closed→open→half-open';open-degradation(キャッシュ/スタブ)
go sem:=make (chan struct{}、64 )//DB/PSPへの競合の制限
func handle (req) {{func handle{
選択してください{
case sem<-struct{}{}:
func(){<-sem}()
ctx、 cancel:=context。WithTimeout (req。ctx、 300時間。ミリ秒)
defer cancel()[defer canc()
res、 err:=db。Do (ctx、 req)
場合err==コンテキスト。DeadlineExceeded{メトリック。タイムアウトです。株式会社()return TooSlow()}
return Ok (res)
デフォルト:
メトリクス。Backpressure。株式会社()
return TooBusy (429"、Retry-After: 0。2")
}
}
6)タイムアウト、リトリート、ジッタ: 「3つのサバイバルクジラ」
SLOより短いタイムアウト:SLO 400ミリ秒の場合、DB/プロバイダへのタイムアウト250-300ミリ秒;合計リクエストタイムアウト<400-600 ms。
Retrai限定とスマート:1-2最大試行、唯一の安全な操作のために(idempotent)、指数とジッタと。
結合:1つのキーのリプレイを集計します。
擬似コード(指数+ジッタ):範囲(0、2)の試行のためのpython:
試してみてください:
return call (dep、 timeout=0。3)
タイムアウト以外:
backoff=(0。05 (2attempt))+ランダム。uniform (0、0。05)
睡眠(バックオフ)
アップストリームを上げる利用不可
7)アイデンティティと重複除外
Idempotency-Key on HTTP (deposits、 payment)、 'operation_id' in the database (unique index)。
受信トレイ/受信トレイ:受信中のWebhook-常に変更不可の受信トレイ・テーブルを介して'event_id';アウトバウンド-トランザクションによるアウトボックスから。
正確に一度の「意味」:配信/実行を繰り返すことができますが、効果は1つだけです。
8)遅い操作のための速いAPI
同期応答:201/202+ステータスURL ('/status/{ id}')、ETAおよびレトロなヒント。
Webhooks/Server-Sent Events/WS-準備ができたら状態をプッシュします。
クライアント規律:'Retry-After'、 idempotence、 polling limit。
レスポンスの例:json
。 。1 202受け入れられました
ロケーション:/v1/withdrawals/req_9f2/status
再試行後:2
{
「request_id": 「req_9f2,」 「state」: 「processing」、 「next_check_sec": 2
}
9)熱い仕事を最小にして下さい
背景に重いものを置く:変換、集計、通知、DWHへの書き込み。
キャッシュと投影:一般的に読まれます-短いTTLとイベント障害を持つキャッシュアサイド。
バッチパターン:グループ外部コール(例:リクエストプロバイダの制限はN msで1回限ります)。
シリアル化:サービスツーサービス通信のための高速コーデック(protobuf/msgpack);エッジ上のJSONのみ。
10)制御の下のDB
接続プール:上限(コア/IOに基づく)、プールへのキューを有効にします。
インデックスと計画:p95はプランの+回帰オートテストを説明します。
リクエストタイムアウト:short、 'statement_timeout' (Postgres)。
ホット行/ロック:キーシャーディング、楽観ロック(バランスバージョン)、「モノリシック」トランザクションの代わりに佐賀。
11) WebSocket/リアルタイム
ニュースレターのリミッター:バッチ放送、接続ごとに最大msgs/秒。
内部バックプレッシャー:キャップ付きのアウトバウンドメッセージキュー;overflow-ドロップ低優先度。
リリース中のスティッキールートとPDB-嵐を再接続させないように。
12)推測しないように観測可能
メトリック(RED/USE+backpressure):- ルート上の'request_rate'、 'error_ratio'、 'latency_p95/p99'
- 'queue_depth'、 'lag_seconds'、 'consumer_inflight'、 'retries_total'、 'dlq_rate'。
- 'backpressure_drops'、 'admission_rejects'、 'circuit_open'。
- 'connections_in_use/max'、 'locks'、 'slow_queries'。
- トレース:'queue→worker→db/psp'タグ'operation_id'、 'partition'、 'retry'にまたがる。
- ログ:構造、'trace_id'、 PIIなし;個々の「オープン/クローズサーキット」イベント。
13)負荷テスト
バーストのオープンモデル(到着/秒)。セッションのクローズドモデル(VU)。
プロフィール:短い破烈60-120 sおよび浸る1-4 h。
注入の失敗:+200-500 msによって外部APIを遅くして下さい、p99/retrai/queuesを見て下さい。
グリーンゾーンの基準:成長がない'queue_lag'、安定したp95、 'dlq_rate≈0'。
14)安全性と信頼性
TLS/mTLSキュー、メッセージ署名、スキーマ監視(Avro/Protobuf+Schema Registry)。
Idempotentプロデューサー(Kafka)、正当化された正確に1回のtx。
カオスモード:定期的に中毒を「ドロップ」し、劣化(回路、フォールバック)を見てください。
15)構成の「部分」の例
Nginx/Envoy入力シェーピング:nginx limit_req_zone$binary_remote_addr zone=api: 10m rate=20r/s;
サーバー{{さーば}}
location/api/{ {location/api/api/{
limit_req zone=api burst=40 nodelay;
proxy_read_timeout 0。6s;#はSLO proxy_connect_timeout 0より短い。2s;
}
}
RabbitMQ(プリフェッチ):
基本的なことです。qos (prefetch_count=32)#CPU/IOバランス
カフカ消費者(Javaフラグメント):
java props。put (ConsumerConfig。MAX_POLL_RECORDS_CONFIG、 200);
小道具だよ。put (ConsumerConfig。 、 ; );
小道具だよ。put (ConsumerConfig。 、 ; );
16)実装チェックリスト(prod-ready)
- クリティカルパスは、同期応答と非同期処理(SEDA)に分けられます。
- 外部依存関係の入場管理と競争制限。
- タイムアウトはSLOより短い;retrai ≤ 2、指数とジッタで;合体しています。
- サーキットブレーカ+劣化(キャッシュ/スタブ)、ハーフオープンポリシー。
- キュー/ストリーム:プリフェッチ/機内、DLQ、キーバッチ。
- Idempotency (operation_id/Idempotency-Key)、 Outbox/Inbox、重複除外。
- キャッシュ:キャッシュアサイド、短いTTL+イベント障害。
- DB:プール制限、statement_timeout、インデックス、アンチロック戦略。
- WS:メッセージ制限、butching、 sticky-routing、 PDB。
- オブザビリティ:backpressure/queues/retriesメトリクス、エンドツーエンドトレイル、ダッシュボード。
- 負荷および故障テスト(open+closed、 burst+soak)、グリーンゾーン基準。
履歴書のサマリー
高速なバックエンドは「別のキャッシュを作る」ではなく、制御されたストリームです。エントリーは制限され、重いです。バックグラウンドでは、キューとリミットを持つ各ステージ、リトレイはまれでスマートであり、チェーンはサーキットブレーカとidempotencyによって保護されます。タイムアウトの規律、観察可能性、定期的なストレステストを追加すると、外部プロバイダのバーストや気まぐれの下でもp95/p99は緑色のままです。