🚀
【データ指向アプリケーション要約】 第9章 一貫性と合意
「第9章 一貫性と合意」は、分散システムでよく出てくる 「データの正しさ(一貫性)」 と 「みんなで同じ決定をする(合意)」 について、濃い内容が詰まった章だった。
だいぶ良かった。(薄い)
要点を押さえながらまとめていく。
1. 一貫性の保証
そもそも一貫性って何?
- 分散システムでは、データがいろんなマシンにコピーされるじゃない?
そのとき「どのマシンを見ても同じ内容が見えるの?」とか「書き込んだはずのデータが、すぐに反映されるの?」みたいな話が出てくる。 - “一貫性”とはつまり「データの見え方がどこまで正しいか」を示すレベルのことだね。
いろんなレベルがある
-
強い一貫性(強整合性): 常に最新状態が全ノードで同じに見える、みたいな理想形。
でも実現コストが高い。 -
最終的に一貫性(Eventual Consistency): 一時的にズレはあるけど、時間が経てば落ち着くよ、的なゆるい整合性。
ほかにも「read-after-write 一貫性」や「モノトニックリード」など、いろんなモデルがあったよね。
9章ではさらに踏み込んで、線形化可能性(linearizability) っていう “めちゃ厳密なモデル” を中心に話が進んでく。
2. 線形化可能性(Linearizability)
「線形化可能性」って聞き慣れない言葉やけど、「どんなに分散してても、まるでひとつのデータベースが瞬時に更新されたように見せる」 という強い一貫性の理論モデルだと思っていい。
2.1 システムを線形化可能にする条件は?
- クライアントがあるオペレーション(読み書き)をしたら、「その時点以降の全ての読み取りは、その結果を反映してる」
- 分散環境で実現しようとすると、ネットワーク遅延や障害を考えてかなり大変
- 実装例:
- シングルリーダーで、リーダーが書き込みを厳密に順序付けして、読み取りは必ずその順序を守るとか
- アトミックな操作(たとえばCompare-and-Setみたいな操作)がちゃんと1回ずつ直列に処理されることを保証するなど
2.2 線形化可能性への依存
- アプリのロジック上、「絶対に古いデータを読んではまずい」ケースや、「Compare-and-Setで同時更新が起きないように制御したい」みたいなときに有効
- ロックや分散ロックを使うときも、内部では線形化を担保するアルゴリズムが動いてたりする
2.3 線形化可能なシステムの実装
- 一番シンプルなのは「リーダーが全部仕切って、書き込みを直列化する」パターン
- ただし高負荷・高遅延になるリスクがあって、スケーラビリティや可用性とのトレードオフがある
2.4 線形化可能にすることによるコスト
- ネットワーク往復が増えたり、ノード障害時に書き込みが止まったり、、、
- 強い保証を得る分、性能の犠牲や 可用性の犠牲 などのコストがかかる
3. 順序の保証
線形化可能性は「システム全体で1つのタイムラインがある」ってイメージやけど、現実の分散システムでは “部分的な順序” しか保証できないケースも多い
3.1 順序と因果関係
- 因果関係: 「Aが起きたからBが起きた」という関係。チャットで「質問」があって「回答」がある、みたいな
- 分散環境だと、AとBのイベントが同時っぽく起きた場合、どっちが先か曖昧になることがある
- “因果一貫性”みたいに、「因果関係のあるイベントは順序を守る」けど、無関係なイベントは順序を厳密にしなくてもOK、という緩やかなモデルもある
3.2 シーケンス番号の順序
- 全てのイベントにシーケンス番号を振って順序づける方法
- ただし分散環境で「絶対一意かつ単調増加な番号」を振るには、やっぱり中央集権的な仕組み(リーダーなど)が必要だったりする
3.3 全順序ブロードキャスト
- “全ノードが同じ順序でメッセージを受け取る”ことを保証する仕組み
- リーダーがメッセージの順番を決めてから各ノードに送る、みたいな実装が代表例
- これも 実装が大変 だし、リーダーが故障したらどうするかなど問題が出てくる
4. 分散トランザクションと合意
4.1 アトミックなコミットと2相コミット(2PC)
-
2相コミット(2-Phase Commit) は、分散トランザクションでおなじみのプロトコル
- まず「みんなコミットOK?」って尋ねて(prepareフェーズ)、全員OKなら「よし、コミットだ!」と確定する(commitフェーズ)
- 誰かがNGを出したら全体をロールバックする
- ただし、2PCはフェイルオーバーに弱い とか、コーディネータ(調整役)が落ちると止まってしまう…といった弱点もある
4.2 分散トランザクションの実際
- 「分散ACIDトランザクション」は便利だけど、システムが大規模になればなるほど遅延や障害の影響が大きい
- なので最近の大規模分散システムでは、「なるべく分散トランザクションを減らす」設計(マイクロサービスっぽい発想)が多い
4.3 耐障害性を持つ合意
- Paxos や Raft といった合意アルゴリズムが有名
- 複数ノードで「この値を正としよう!」と決めるときに、少数のノード障害やネットワーク障害があっても合意できる仕組み
- この合意アルゴリズムを使ってリーダー選出や設定変更を安全に行うことが多い
4.4 メンバーシップと協調サービス
- 分散システムで「今、どのノードが参加してるの?」とか、設定ファイルなどのグローバル情報を安全に共有するために、Zookeeper や etcd みたいな「協調サービス」(コーディネーションサービス)がよく使われる
- これらのサービスの中核にも、Paxos/RAFTみたいな合意アルゴリズムが入ってる
まとめ
-
一貫性(Consistency): 分散システムで「どこまで正しく最新状態を見せるか」をどう保証するか
- 特に「線形化可能性(Linearizability)」は最強レベルの一貫性モデルだけど、コストも高い
-
順序(Ordering): イベントの因果関係や全順序をどう保つか
- 全順序ブロードキャストは便利だけど、実装も運用も大変
-
合意(Consensus): 分散システムが「この値」「この状態」で一致しよう、と決める仕組み
- 2PCやPaxos、Raftなど。トランザクションのコミットやリーダーの選出に使われる
- 線形化可能性や合意を強くすると、どうしても性能や可用性が下がる
- だから分散アプリケーションは、どの部分に強い一貫性が必要か、どの部分は多少緩くてもOKかを見極めるのが大事
Discussion