🎓 レベル:標準 | 重要度:B(重要)
📎 前提:RPCとRMI | 関連:配送保証(at-most-once・at-least-once・exactly-once)・分散トランザクションとSaga
要点(BLUF)
- 非同期メッセージングは、送り手と受け手の間にメッセージブローカ(キュー)を挟み、両者を時間的・空間的に切り離す通信様式。送ったら待たずに次へ進める。
- 代表モデルは2つ:ポイントツーポイント(キュー)=1メッセージを1コンシューマが処理、pub/sub(トピック)=1メッセージを複数購読者へ配信。
- 利点は疎結合・バースト吸収・耐障害(受け手停止中もキューに溜まる)。代償は順序保証・配送保証・重複・遅延の扱いが難しくなること。
問題設定 ── 同期呼び出しの弱点
RPC(RPCとRMI)の同期呼び出しは、呼び先が落ちると呼び元も詰まり、障害が連鎖します(カスケード障害)。負荷スパイクも吸収できない。送り手と受け手を切り離したい——これがメッセージングの動機です。
仕組み ── キューとpub/sub
flowchart LR
P["プロデューサ"] -->|"publish"| BR["ブローカ(キュー/トピック)"]
BR -->|"deliver"| C1["コンシューマ1"]
BR -->|"deliver(pub/subなら複製)"| C2["コンシューマ2"]
BR -.->|"受け手停止中は滞留(耐障害)"| BR
- キュー(P2P):1メッセージは1コンシューマが取得・処理(ワークキュー、負荷分散)。
- pub/sub(トピック):発行は全購読者に届く(イベント配信、ファンアウト)。
- バックプレッシャ:受け手が遅いとき、キュー長で送り手を抑制(溢れ対策)。無いと溢れて落ちる。
要するに何か:ブローカという緩衝材を挟むことで、「相手が今いるか/速いか」に依存せず送れる。時間的・空間的・同期的の3つの結合を外す。
正しさの観点 ── 何を保証し、何を諦めるか
- 配送保証:多くのブローカは既定で at-least-once(配送保証(at-most-once・at-least-once・exactly-once))。重複が来る前提でコンシューマを冪等に作る。
- 順序保証:全体順序は重い。パーティション内のみFIFO(Kafkaのパーティション、同一キーは同一パーティション)が現実解。
- 耐久性:ブローカがディスクに永続化すれば、受け手停止中もメッセージは残る(ロールバック・再処理が可能)。
順序と並列度はトレードオフ:厳密順序を求めると並列に捌けず、並列で捌くと順序が乱れる。だから「順序が必要な単位(キー)でパーティション」する設計が要ります。
他手法との比較
| 観点 | RPC(同期) | メッセージング(非同期) |
|---|---|---|
| 結合 | 密・即応答 | 疎・後で処理 |
| 障害の波及 | 連鎖しやすい | キューが吸収 |
| 順序 | 自然(1呼び出し) | パーティション単位で工夫 |
| 即時性 | 高い | 遅延が入る |
なぜ分散だと難しいか(直観)
切り離す代わりに、「送ったのに処理されたか分からない」状態が設計の常態になります。だから「送って忘れる」ではなく「送って、いつか・1回以上・冪等に処理される」を前提に組む。pub/subのファンアウトでは、ある購読者だけ失敗する部分配送も起き、再送と冪等性が一段重要になります。
⚠️ よくある誤解・落とし穴
- 「キューに入れたら届いたも同然」→ コンシューマがack前に落ちれば再配送で重複。冪等性が要る。
- 「全メッセージが順序通り」→ 並列消費すると順序は崩れる。順序が要る範囲をキーで束ねる。
- 「exactly-once配送がある」→ 配送レベルのexactly-onceは一般に不可能に近い。処理の冪等化で実効的に1回にする(配送保証(at-most-once・at-least-once・exactly-once))。
- 「ブローカは単一障害点」→ ブローカ自体をクラスタ化・レプリケーション(レプリケーション方式(同期/非同期・リーダー/リーダーレス))して冗長化する。
対応ラボ
なし(概念回)。at-least-once+冪等化の効果は 配送保証(at-most-once・at-least-once・exactly-once) のラボで実証します。
関連
- 同期呼び出しの様式が RPCとRMI
- 重複への王道が 配送保証(at-most-once・at-least-once・exactly-once)
- Saga はメッセージ駆動の長期トランザクション 分散トランザクションとSaga