- API
- ネットワーク
- 技術 💻
分散システムの落とし穴8選|冪等性・リトライ・CAP定理
サーバーが2台になった瞬間、世界のルールが変わるんですよね。
メッセージは重複するし、時計は合わないし、「死んだ」と「遅い」の区別がつかない。単一サーバーの常識が、ぜんぶ通用しなくなります。今回は、「二重課金」と「たまに消えるデータ」の生まれる場所から、マイクロサービスやAPI連携を作る人に効くものを8つ集めました。1つでも知らなかったら儲けものです。
① 「ちょうど1回だけ届ける」は、幻想です
分散システムの一番深い真実が、これです。
ネットワーク越しのメッセージ配送で、「ちょうど1回(exactly once)」を完全に保証することはできません。
送信して応答が来なかったとき、相手に「届いていない」のか「届いたが応答だけ失われた」のか、送り手には区別できないからです。再送すれば重複し、再送しなければ欠落する。
だから現実の設計は、「最低1回は届ける+受け手が重複を無害化する」の組み合わせになります。次の②が、その相棒です。
② 二重課金を防ぐのは、「冪等性」です
①の帰結です。メッセージは重複して届く前提で作る。
そこで効くのが冪等性(べきとうせい)——同じ処理を2回実行しても、1回と同じ結果になる性質です。
実装の定番は、リクエストに一意のIDを付けること。受け手は「このIDは処理済みか」を確認してから実行します。決済APIが「冪等性キー」を要求するのは、まさにこれなんですよね。
リトライを書くなら、冪等性とセット。片方だけだと、リトライが二重課金製造機になります。
③ サーバー同士の時計は、合っていません
複数サーバーのログを時刻で並べて、「こっちが先に起きたはず」——危ない推理です。
各サーバーの時計は、時刻同期(NTP)をしていてもミリ秒単位ではズレています。ズレは変動もします。
つまり分散システムでは、タイムスタンプの前後関係=実際の前後関係ではありません。障害調査で時系列を組み立てるときの、大前提です。
順序が本当に大事な場面では、時刻ではなく連番や論理的な順序づけで管理する。時計を信じない設計が、分散の作法なんです。
④ 「ネットワークは信頼できる」から始まる、8つのウソ
分散システムには、有名な「分散コンピューティングの8つの誤謬」というリストがあります。
- ネットワークは信頼できる
- 遅延はゼロ
- 帯域は無限
- ネットワークは安全
- 構成は変わらない
- 管理者は1人
- 転送コストはゼロ
- ネットワークは均質
——全部、ウソです。
分散システムに初めて触れる人がやりがちな思い込みとして1990年代に整理されたものですが、クラウド時代のいまも一言一句そのまま通用します。設計レビューのチェックリストとして、「この設計、8つのどれかを信じていないか?」と問えるんです。
⑤ 「死んだ」と「遅い」は、区別できません
相手サーバーから応答がない。落ちたのか、単に遅いのか。
外から見る限り、この2つは原理的に区別できません。だからすべての待ちにはタイムアウトが要り、タイムアウトは「諦める時間を自分で決める」という設計判断になります。
怖いのは、遅いだけの相手を「死んだ」と判断して切り替えた直後に、本人が復活するケース。処理が二重に走ります。
タイムアウト値は設定ではなく設計。「何秒で諦めて、諦めた後どうするか」までがセットなんです。
⑥ リトライは、障害を大きくすることがあります
エラーになったらリトライ。正しい姿勢ですが、集団でやると凶器になります。
サーバーが一瞬詰まったとき、全クライアントが同時にリトライすると、負荷が倍増して完全に沈みます。復活しかけたところに再突撃が来る。リトライストームです。
定石は2つあります。
- エクスポネンシャルバックオフ:間隔を指数的に伸ばす
- ジッター:待ち時間をランダムにずらす
全員が同時に戻ってこないようにするんですよね。「エラー時は3回リトライ」とだけ書かれた設計書を見たら、この2つを確認するタイミングです。
⑦ ネットワークが裂けると、リーダーが2人になります
サーバー群の間のネットワークが分断されると、恐ろしいことが起きます。
分断された両側が、それぞれ「相手が死んだ。自分が代表だ」と判断する——スプリットブレインです。2つの「正」が生まれ、データが枝分かれします。
対策の定番が多数決(クォーラム)。全体の過半数と通信できる側だけが代表になれるルールにすれば、代表は最大1人に絞られます。
クラスタ構成のノード数が奇数(3台、5台)なのは、多数決を成立させるためなんです。
⑧ 分断が起きたら、「正しさ」と「応答」は両立しません
⑦の状況を、理論として言い切ったのがCAP定理です。
ネットワーク分断が起きている間、システムは「一貫性(全員が同じ最新データを見る)」と「可用性(常に応答を返す)」のどちらかを諦めるしかありません。両取りは不可能です。
銀行の残高なら、応答を止めてでも一貫性を守る。SNSのタイムラインなら、多少古くても応答を返す。
「分断のとき、うちはどちらを捨てるのか」。この問いに答えを持っているかが、分散設計の成熟度なんです。
番外編:知っておくと会話が深くなる話
第一原則は「分散させないこと」
マーチン・ファウラーが唱えた「分散オブジェクト設計の第一法則:分散させるな」という、身も蓋もない教えがあります。1台で足りるなら1台が最強。分散は、必要に迫られて払うコストなんですよね。
光は1ナノ秒で、30cmしか進めません
計算機科学者グレース・ホッパーは、約30cmのワイヤを配って「これが1ナノ秒です」と説明しました。東京〜大阪間の往復は、物理法則として数ミリ秒を下回れない。遅延は設定ではなく、光の速さなんです。
マイクロサービスは、組織の話でもあります
「システムの構造は、組織のコミュニケーション構造に似る」という法則(コンウェイの法則)があります。分散アーキテクチャの議論が、いつの間にかチーム分割の議論になるのは、必然なんですね。
RJCでも、分散と向き合っています
RJCが携わる決済や交通のシステムは、外部サービスとの連携が止まらないことが前提の世界です。リトライと冪等性の設計は、そのまま品質になるんですよね。
こういう仕組みの話を、Techチームで共有しながら開発しています。
よくいただくご質問
Q. まずどれから押さえるべきですか?
A. ①②のセットかなと思います。「重複前提+冪等性」は、外部API連携を書く全員に今日から効きます。
Q. マイクロサービスにすべきか迷っています…
A. 番外編の第一原則をおすすめします。分散は解決策であると同時にコストなので、「分けないと困る理由」が言えるまでは1つでいいと思うんですよね。
Q. 障害調査のコツはありますか?
A. ③を思い出してください。複数サーバーのログを時刻だけで並べない。リクエストIDで追跡できる仕組みを先に入れておくのが、一番の近道です。
Q. 未経験からでも、分かるようになりますか?
A. なります。「手紙が届かないかもしれない世界で、どう約束を守るか」という思考実験なので、図を描けば必ず追えます。
ネットワークの向こうを、信じすぎない
今日の8つに共通していたのは、これでした。
届いたか分からない。時計は合わない。死んだか遅いか分からない。分散システムの設計は、疑うことから始まります。
そして疑った分だけ、冪等性・タイムアウト・多数決という道具で守る。疑い方を知っている人が、落ちないシステムを作るんですよね。
みなさんが踏んだ分散の事故、よかったら教えてください。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。