Skip to content
Published on

分散システムの基礎完全ガイド:CAP定理から合意アルゴリズム、一貫性モデルまで

Authors

目次

1. なぜ分散(ぶんさん)システムなのか

1.1 分散システムの必要性

単一サーバーでは現代サービスの要求を満たせません。分散システムが必要な3つの核心的理由があります。

スケーラビリティ(拡張性): トラフィックが増加すると単一サーバーのCPU、メモリ、ディスクには限界があります。水平スケーリング(スケールアウト)で複数サーバーに負荷を分散します。

可用性(かようせい): サーバーが1台(だい)落ちてもサービスが継続動作する必要があります。Netflix、Googleなどのサービスは99.99%以上の可用性を目標としています。

耐障害性(たいしょうがいせい): ネットワーク断絶(だんぜつ)、ディスク障害、データセンター火災など、障害は必ず発生します。分散システムはこのような障害に耐えられるよう設計されます。

1.2 分散システムの課題

単一サーバー                  分散システム
+-----------+               +-----+  +-----+  +-----+
|  App + DB |    vs         | N1  |--| N2  |--| N3  |
+-----------+               +-----+  +-----+  +-----+
                                  \    |    /
                             ネットワーク(不安定)

分散システム固有の課題:

  • ネットワーク遅延: ノード間通信にms〜秒単位の遅延が発生
  • 部分障害(ぶぶんしょうがい): 一部のノードだけがダウンし残りは正常動作
  • 時計同期不可: 各ノードの物理時計に微小なずれ
  • ビザンチン障害: ノードが誤ったデータを送信する可能性

2. CAP定理(ていり)

2.1 CAP定理とは?

2000年にEric Brewerが提案し、2002年にSeth GilbertとNancy Lynchが証明した定理です。

分散システムは以下の3つの性質のうち最大2つまで同時に保証できます:

性質説明
Consistency(一貫性)すべてのノードが同じ時点で同じデータを見る
Availability(可用性)すべてのリクエストが応答を受け取る
Partition Tolerance(分断耐性)ネットワーク分断でもシステムが動作する

2.2 なぜ3つ全部は持てないのか — 直感的証明

ネットワーク分断発生!

  [Node A]  ----X----  [Node B]
  data=1                data=1

  ClientがNode Aにwrite(data=2)をリクエスト

  選択肢1 (CP): Node Bと同期不可 → リクエスト拒否(可用性を犠牲)
  選択肢2 (AP): Node Aだけ更新 → 不整合を許容(一貫性を犠牲)

ネットワーク分断(P)は分散システムで不可避なため、実質的にCP vs APの選択です。

2.3 CPシステム vs APシステム

特性CPシステムAPシステム
分断時の動作書込み拒否または待機書込み許可、後で統合
ZooKeeper, etcd, SpannerCassandra, DynamoDB, Riak
適合ケース金融取引、リーダー選出SNS、ショッピングカート

2.4 PACELC拡張(かくちょう)

CAPの限界を補うPACELCモデル:

if (Partition) then
    Availability vs Consistency
else
    Latency vs Consistency
システムP発生時正常時
CassandraPA(可用性)EL(低遅延)
SpannerPC(一貫性)EC(一貫性)
MongoDBPA(可用性)EC(一貫性)

3. 一貫性(いっかんせい)モデル

3.1 一貫性レベル比較

強い順に:

厳密な一貫性(Strict)
線形化可能性(Linearizability)
順序一貫性(Sequential)
因果一貫性(Causal)
結果整合性(Eventual)

3.2 Strong Consistency(強い一貫性)

すべての読み取りが最新の書き込み結果を返します。

時間 →
Client A:  write(x=1) ------>
Client B:              read(x) → 必ず1を返す
  • 実装:すべてのノードに同期レプリケーション後に応答
  • 利点:プログラミングモデルが単純
  • 欠点:高遅延、低可用性

3.3 Sequential Consistency(順序一貫性)

すべてのノードが同じ順序で操作を見ます。ただしリアルタイムの順序とは異なる場合があります。

実時間:     A:write(x=1)  B:write(x=2)
順序一貫性: B:write(x=2), A:write(x=1) も許可
           (すべてのノードがこの順序に同意すれば)

3.4 Causal Consistency(因果一貫性)

因果関係のある操作は順序が保証されます。因果関係のない操作は異なる順序で見える場合があります。

Aが投稿を作成 → Bがコメントを作成(因果関係あり)
  → すべてのノードで投稿がコメントより先に見える

Cが投稿作成 / Dが別の投稿作成(因果関係なし)
  → ノードごとに順序が異なる可能性あり

3.5 Eventual Consistency(結果整合性)

更新が停止すれば最終的にすべてのノードが同じ値を持ちます。

時間 →
Node A:  x=1 ......... x=1(変更伝播) → x=1
Node B:  x=0 ......... x=0 → x=1(若干の遅延後)
Node C:  x=0 ......... x=0 → x=1
  • DNS、CDNキャッシュ、Amazon S3などで使用
  • 競合解決戦略が必要:Last-Write-Wins、CRDT、アプリケーションレベルのマージ

3.6 一貫性モデル比較表

モデル遅延可用性プログラミング難易度ユースケース
Strong簡単金融、在庫
Sequential中程度分散ロック
Causal中程度SNSフィード
Eventual非常に低非常に高難しいDNS、キャッシュ

4. レプリケーション(複製)

4.1 Leader-Followerレプリケーション

最も一般的なレプリケーション方式です。

           書込み
Client[Leader] → 複製 → [Follower 1]
[Follower 2]
[Follower 3]
           読取り
Client[Follower 1, 2, 3のいずれか]

同期レプリケーション: リーダーがすべてのフォロワーの確認を待ってから応答。強い一貫性、高遅延。

非同期レプリケーション: リーダーが即座に応答、フォロワーは後で複製。低遅延、データ損失の可能性。

半同期レプリケーション: 最低1つのフォロワーの確認後に応答。MySQL、PostgreSQLのデフォルト方式。

# 半同期レプリケーション擬似コード
def write(data):
    leader.write(data)
    ack_count = 1  # リーダー自身
    for follower in followers:
        if follower.replicate(data):
            ack_count += 1
            if ack_count >= 2:  # 最低1つのフォロワー確認
                return SUCCESS
    return FAILURE

4.2 Multi-Leaderレプリケーション

複数ノードが同時に書込みを受け付けます。

[Leader A] ←→ [Leader B] ←→ [Leader C]
    ↓              ↓              ↓
[Follower]    [Follower]    [Follower]
  • ユースケース:マルチデータセンター、オフライン作業(Google Docs)
  • 核心的課題:書込み競合の解決
    • Last-Write-Wins(LWW):タイムスタンプが大きい書込みが勝利
    • マージ:CRDT(Conflict-free Replicated Data Type)を使用
    • ユーザー解決:競合をユーザーに見せて選択させる

4.3 Leaderlessレプリケーション(Quorum)

リーダーなし、クライアントが複数ノードに同時に読み書きします。

         write(x=1)
Client[Node A] OK
[Node B] OK
[Node C] NG(障害)

W=2成功 → 書込み成功!

         read(x)
Client[Node A] x=1
[Node B] x=1
[Node C] x=0(古い値)

R=2 → 最新値(x=1)を返す

Quorum公式: W + R > Nなら最新データの読み取りを保証

設定NWR特性
強い一貫性322一貫性保証
高速書込み313書込み高速、読取り低速
高速読取り331書込み低速、読取り高速
  • Cassandra、DynamoDB、Riakで使用
  • アンチエントロピー、読取り修復で不整合を解決

5. パーティショニング(シャーディング)

5.1 なぜパーティショニングか

データが単一ノードの容量を超えた場合、複数ノードに分散して保存します。

5.2 ハッシュパーティショニング

hash(key) mod N = partition_number

key="user_123" → hash → 77 mod 3 = 1Partition 1
key="user_456" → hash → 22 mod 3 = 2Partition 2
  • 利点:データの均等分配
  • 欠点:範囲クエリが非効率、ノード追加/削除時に大量の再配置

5.3 範囲パーティショニング

Partition 0: A-F
Partition 1: G-M
Partition 2: N-S
Partition 3: T-Z
  • 利点:範囲クエリが効率的
  • 欠点:ホットスポット発生の可能性(特定範囲にデータ集中)

5.4 コンシステントハッシング

ノード追加/削除時に最小限のキーだけ再配置します。

        0
       / \
     330   30
     /       \
   300        60
   |    Ring    |
   270        90
     \       /
     240   120
       \ /
       180

Node A: 0-90
Node B: 90-180
Node C: 180-270
Node D: 270-360

Node E追加(位置135) → Node B90-135だけNode Eに移動
  • 仮想ノード(Virtual Node)で不均衡を解消
  • Cassandra、DynamoDB、Memcachedで使用

5.5 リバランシング戦略

戦略説明
固定パーティション数最初からパーティション数を固定、ノードに分配Elasticsearch, Riak
動的分割パーティションサイズ基準で分割/統合HBase, RethinkDB
ノード比例ノード数に比例してパーティション数を決定Cassandra

6. 合意(ごうい)アルゴリズム(Consensus)

6.1 合意問題とは?

分散システムのすべてのノードが1つの値に合意すること。リーダー選出、アトミックコミット、分散ロックなどに必須。

6.2 Paxosの基礎

Leslie Lamportが1989年に提案。理解が難しいことで有名です。

3つの役割

  • Proposer:値を提案
  • Acceptor:値を受け入れ/拒否
  • Learner:合意された値を学習

2つのフェーズ

Phase 1: Prepare
  ProposerAcceptor: 「提案番号nを準備してください」
  AcceptorProposer:OK」(以前受け入れた値があれば一緒に伝達)

Phase 2: Accept
  ProposerAcceptor: 「提案番号n、値vを受け入れてください」
  AcceptorProposer: 「受入済」(過半数が受入れれば合意完了)
  • 問題点:ライブロック発生の可能性、Multi-Paxosで解決

6.3 Raft詳細

Diego OngaroとJohn Ousterhoutが2014年に提案。Paxosより理解しやすく設計。

核心概念: リーダーベースの合意

ノード状態: Leader、Follower、Candidate

6.3.1 リーダー選出(Leader Election)

時間 →
           Term 1          Term 2
Follower: [Heartbeat]... [Timeout!]Candidate
Candidate: 自分に投票 + 他ノードにRequestVote
           過半数得票 → Leader当選!

Leader:   [Heartbeat][Heartbeat][Heartbeat]...
# Raftリーダー選出擬似コード
class RaftNode:
    def __init__(self):
        self.state = "follower"
        self.current_term = 0
        self.voted_for = None
        self.election_timeout = random(150, 300)  # ms

    def on_timeout(self):
        self.state = "candidate"
        self.current_term += 1
        self.voted_for = self.id
        votes = 1  # 自分自身

        for peer in self.peers:
            if peer.request_vote(self.current_term, self.log):
                votes += 1

        if votes > len(self.peers) // 2:
            self.state = "leader"
            self.send_heartbeats()

6.3.2 ログレプリケーション(Log Replication)

ClientLeader: write(x=5)

Leader Log: [Term1:x=3] [Term1:y=7] [Term2:x=5]
AppendEntries
Follower1: [Term1:x=3] [Term1:y=7] [Term2:x=5] OK
Follower2: [Term1:x=3] [Term1:y=7] [Term2:x=5] OK
Follower3: [Term1:x=3] [Term1:y=7] (ネットワーク遅延)

過半数(3/5)複製完了 → コミット! → クライアントに応答

6.3.3 安全性の保証(Safety)

  • Election Safety: 1つのTermに最大1人のリーダー
  • Leader Append-Only: リーダーはログを上書き/削除しない
  • Log Matching: 同じインデックスと同じTermのエントリがあれば、それ以前のエントリもすべて同一
  • State Machine Safety: コミットされたエントリはすべてのノードで同じ順序で適用

6.4 Raftの使用事例

システム用途
etcdKubernetesクラスター状態の保存
Consulサービスディスカバリ、KVストア
CockroachDB分散SQLデータベース
TiKVTiDBの分散KVストア

7. 分散トランザクション

7.1 2PC(Two-Phase Commit)

Phase 1: Prepare(投票)
  CoordinatorParticipant A: 「コミット可能?」
  CoordinatorParticipant B: 「コミット可能?」
  ACoordinator: 「Yes」
  BCoordinator: 「Yes」

Phase 2: Commit(実行)
  CoordinatorA: 「コミット!」
  CoordinatorB: 「コミット!」

問題点

  • コーディネーターが単一障害点(SPOF)
  • ブロッキング:Prepare後にコーディネーターが障害を起こすと参加者が無限待機
  • 性能:同期プロトコルのため低速

7.2 3PC(Three-Phase Commit)

2PCのブロッキング問題を解決するためにPre-Commitフェーズを追加。

Phase 1: CanCommit
Phase 2: PreCommit(タイムアウト設定)
Phase 3: DoCommit
  • ネットワーク分断時にはまだ不整合の可能性あり
  • 実務ではほとんど使用されない

7.3 Sagaパターン

長いトランザクションを複数のローカルトランザクションに分割し、失敗時に補償トランザクションを実行。

注文作成Saga:

T1: 注文作成 → T2: 決済処理 → T3: 在庫差引 → T4: 配送開始
                     ↓ 失敗!
C2: 決済取消 ← C1: 注文取消

2つの実装方式

方式説明トレードオフ
Choreographyイベント駆動、各サービスが次のイベントを発行シンプル、低結合度。追跡が困難
Orchestration中央オーケストレーターが順序を制御追跡が容易、中央集中リスク
# Saga Orchestrator擬似コード
class OrderSaga:
    steps = [
        ("create_order", "cancel_order"),
        ("process_payment", "refund_payment"),
        ("update_inventory", "restore_inventory"),
        ("arrange_shipping", "cancel_shipping"),
    ]

    def execute(self):
        completed = []
        for action, compensation in self.steps:
            try:
                getattr(self, action)()
                completed.append(compensation)
            except Exception:
                # 補償トランザクションを逆順実行
                for comp in reversed(completed):
                    getattr(self, comp)()
                raise SagaFailed()

8. 分散時計(Distributed Clocks)

8.1 物理時計の問題

  • NTP同期誤差:数ms〜数百ms
  • クロックドリフト:時間の経過とともに徐々にずれる
  • うるう秒:稀に1秒が追加/削除される

結論:物理時計だけではイベントの順序を正確に判断できません。

8.2 Lamport Clock(論理的時計)

Leslie Lamportが1978年に提案。各プロセスがカウンターを維持します。

ルール:
1. イベント発生時にカウンターをインクリメント
2. メッセージ送信時に自身のカウンターを含める
3. メッセージ受信時にmax(自身カウンター, 受信カウンター) + 1

Process A:  (1) (2) (3)────→ (6)
                       send     recv
Process B:       (1) (2) (4) (5)
                       recv     send
  • 限界:因果関係は分かるが、2つのイベントが並行(concurrent)かどうかは不明

8.3 Vector Clock(ベクトル時計)

各ノードがすべてのノードのカウンターをベクトルとして維持します。

3ノード A, B, C

A: [1,0,0][2,0,0][2,0,0] Bに送信
B: [0,0,0][0,1,0][2,2,0] Aから受信 → [2,3,0] Cに送信
C: [0,0,0][0,0,1][2,3,2] Bから受信

並行性の判断

  • V1 <= V2:V1のすべての要素がV2以下 — V1はV2より先(happens-before)
  • V1とV2が比較不可能 — 並行(concurrent)イベント
def compare_vector_clocks(vc1, vc2):
    """ベクトル時計の比較"""
    less = False
    greater = False
    for a, b in zip(vc1, vc2):
        if a < b:
            less = True
        elif a > b:
            greater = True

    if less and not greater:
        return "BEFORE"      # vc1 < vc2
    elif greater and not less:
        return "AFTER"       # vc1 > vc2
    elif not less and not greater:
        return "EQUAL"
    else:
        return "CONCURRENT"  # 並行イベント!

8.4 Hybrid Logical Clock(HLC)

物理時計と論理時計の組み合わせ。CockroachDB、MongoDBで使用。

HLC = (物理的時間, 論理的カウンター)

物理的時間が同じ場合、論理的カウンターで順序を決定
NTP誤差範囲内で因果関係を保証

9. 障害検出(しょうがいけんしゅつ)

9.1 ハートビート方式

Node A → 「生きてる?」 → Node B
Node A ← 「うん!」 ← Node B

... タイムアウト ...

Node A → 「生きてる?」 → Node B
Node A ← (無応答) ← Node B
Node B障害と判断
  • 単純だが、ネットワーク遅延時に誤検知(False Positive)が発生
  • タイムアウト設定が重要:短すぎると誤検知、長すぎると検出遅延

9.2 Phi Accrual Failure Detector

ハートビート到着時間の分布を学習し、障害確率を計算します。

Phi(φ):
  φ = 110%の確率で障害
  φ = 21%の確率で障害
  φ = 30.1%の確率で障害

閾値(例:φ > 8)を超えたら障害と判断
  • Cassandra、Akkaで使用
  • ネットワーク状態に適応的に反応

9.3 SWIMプロトコル

Scalable Weakly-consistent Infection-style Membership。効率的なグループメンバーシッププロトコル。

1. Node AがNode Bにping
2. 応答なし → Node C, Dに「Bにindirect pingして」と依頼
3. C, DBにping → 応答なしならBを疑い(suspect)
4. 一定時間後もまだ応答なしならBを除去
5. ゴシップでメンバーシップ変更を伝播
  • O(log N)ラウンドですべてのノードに伝播
  • HashiCorp Memberlist、Consulで使用

10. 実際のシステム分析

10.1 Apache Cassandra(APシステム)

アーキテクチャ:
  - Leaderless、コンシステントハッシング
  - Quorum読取り/書込み(W + R > N  - ゴシッププロトコルでメンバーシップ管理
  - Last-Write-Wins競合解決
  - SSTable + Memtableストレージ

PACELC: PA/EL
  - 分断時:可用性優先
  - 正常時:低遅延優先

10.2 Google Spanner(CPシステム)

アーキテクチャ:
  - 全世界分散、強い一貫性
  - TrueTime APIGPS + 原子時計で時間不確実性区間を提供
  - Paxosベースのレプリケーション
  - 外部一貫性(External Consistency)を保証

TrueTime:
  TT.now()[earliest, latest]
  不確実性区間は通常1-7ms

  トランザクションコミット時:
  1. タイムスタンプsを割り当て
  2. commit-wait:TT.after(s)trueになるまで待機
  3. 不確実性区間分だけ待機して順序を保証

10.3 Amazon DynamoDB(APシステム)

アーキテクチャ:
  - コンシステントハッシング + 仮想ノード
  - Sloppy Quorum:障害時に他のノードが代わりに応答
  - Hinted Handoff:復旧後に元のノードにデータを引き渡し
  - Vector Clockでバージョン管理
  - Merkle Treeでアンチエントロピー

10.4 システム比較表

特性CassandraSpannerDynamoDB
CAP分類APCPAP
一貫性TunableStrongTunable
レプリケーションLeaderlessPaxosLeaderless
パーティショニングConsistent HashRangeConsistent Hash
時計NTPTrueTimeVector Clock
クエリ言語CQLSQLPartiQL

11. DDIA核心要約

Martin Kleppmannの「Designing Data-Intensive Applications」の核心内容:

Part 1: データシステムの基礎

核心キーワード
1章信頼性、拡張性、保守性
2章リレーショナル vs ドキュメント vs グラフモデル
3章ストレージエンジン:B-Tree vs LSM-Tree
4章エンコーディング:JSON、Protobuf、Avro

Part 2: 分散データ

核心キーワード
5章レプリケーション:Leader-Follower、Leaderless
6章パーティショニング:Hash、Range
7章トランザクション:ACID、分離レベル
8章分散システムの困難さ
9章一貫性と合意

Part 3: 派生データ

核心キーワード
10章バッチ処理:MapReduce
11章ストリーム処理:イベントソーシング
12章データシステムの未来

12. 面接質問15選

Q1. CAP定理を説明し、実際のシステムでの適用例を挙げてください。

CAP定理は、分散システムにおいて一貫性(Consistency)、可用性(Availability)、分断耐性(Partition Tolerance)のうち最大2つまで同時に保証できるという定理です。ネットワーク分断は避けられないため、実質的にCP(一貫性優先)とAP(可用性優先)の選択になります。ZooKeeperはCPシステムでリーダー選出や分散ロックに適し、CassandraはAPシステムで高い書込みスループットが必要な場合に適しています。

Q2. Raft合意アルゴリズムのリーダー選出プロセスを説明してください。

Raftでは、フォロワーがelection timeout内にリーダーからのハートビートを受信しないと候補者(Candidate)になります。候補者はTermを増加させ、自分に投票した後、他のノードにRequestVote RPCを送信します。過半数の投票を得るとリーダーになり、即座にハートビートを送信してリーダーシップを通知します。各Termに最大1人のリーダーしか存在できません。

Q3. Eventual ConsistencyとStrong Consistencyの違いを説明してください。

Strong Consistencyはすべての読取りが最新の書込み結果を返すことを保証します。同期レプリケーションが必要で遅延が高く可用性が低くなります。Eventual Consistencyは更新停止後、最終的にすべてのレプリカが同じ値に収束することを保証します。中間で古いデータを読む可能性がありますが、遅延が低く可用性が高いです。DNS、キャッシュシステムで主に使用されます。

Q4. コンシステントハッシングを説明し、仮想ノードがなぜ必要かを述べてください。

コンシステントハッシングはハッシュ空間をリング状に構成し、ノード追加/削除時に最小限のキーだけを再配置する方式です。キーとノードを同じハッシュ関数でマッピングし、キーは時計回りで最も近いノードに割り当てられます。仮想ノード(Virtual Node)は物理ノードが複数のハッシュ位置を持つようにし、データ分布の不均衡を解消します。

Q5. 2PCとSagaパターンの違いを説明してください。

2PC(Two-Phase Commit)はコーディネーターがすべての参加者にprepare/commitを指示してアトミックコミットを保証します。同期的でブロッキングであり、コーディネーターがSPOFです。Sagaパターンは長いトランザクションをローカルトランザクションチェーンに分割し、失敗時に補償トランザクションを逆順実行します。非同期的で拡張性が高いですが、分離性は保証されません。

Q6. Vector ClockがLamport Clockより優れている点は?

Lamport Clockはイベント順序(happens-before)を判断できますが、2つのイベントが並行(concurrent)かどうかは分かりません。Vector Clockは各ノードがすべてのノードのカウンターをベクトルとして保持し、並行性を正確に判断できます。ベクトル比較が不可能な場合、2つのイベントは並行であり、競合解決が必要です。

Q7. Leader-Follower、Multi-Leader、Leaderlessレプリケーションの長所と短所を比較してください。

Leader-Followerは単一書込みポイントで競合がありませんが、リーダーがSPOFで書込みスケーリングが困難です。Multi-Leaderはマルチデータセンターで書込み遅延が低いですが、競合解決が複雑です。Leaderlessは高い可用性と書込みスループットを提供しますが、Quorum設定と競合解決が必要です。

Q8. PACELCモデルがCAPをどのように拡張するか説明してください。

PACELCはネットワーク分断(P)時の可用性(A)vs 一貫性(C)の選択に加え、正常(E: else)状態での遅延(L)vs 一貫性(C)のトレードオフを追加します。CassandraはPA/EL(分断時は可用性、正常時は低遅延)で、SpannerはPC/EC(常に一貫性)です。

Q9. Google SpannerのTrueTimeが強い一貫性をどのように保証するか説明してください。

TrueTimeはGPSと原子時計を使用して時間不確実性区間を提供します。トランザクションコミット時にタイムスタンプを割り当て、commit-waitで不確実性区間分だけ待機します。これにより後でコミットされたトランザクションが必ずより大きなタイムスタンプを持ち、全世界的に外部一貫性が保証されます。

Q10. Quorum読取り/書込みでW + R > Nがなぜ一貫性を保証するのですか?

Nノードに対してWノードに書き込み、Rノードから読み取る場合、W + R > Nなら書込みセットと読取りセットに必ず共通部分が存在します。この共通ノードが最新データを持っているため、読取り時に最新値を返すことができます。例えばN=3、W=2、R=2なら最低1ノードが共通です。

Q11. 分散システムでSplit-Brain問題をどのように解決しますか?

Split-Brainはネットワーク分断により2つのパーティションがそれぞれ自分がリーダーだと判断する状況です。解決方法:Quorumベースのリーダー選出(過半数のないパーティションはリーダー選出不可)、Fencing Token(旧リーダーのリクエストを拒否)、STONITH(疑わしいノードを強制終了)などがあります。

Q12. LSM-TreeとB-Treeの違いを分散システムの観点から説明してください。

LSM-Treeは書込み最適化構造で、すべての書込みがシーケンシャルであり、Compactionで整理します。書込み集中ワークロード(Cassandra、HBase)に適しています。B-Treeは読取り最適化構造でin-place updateを行います。読取り集中ワークロード(従来のRDBMS)に適しています。分散環境ではLSM-Treeはレプリケーション遅延が少なく、高い書込みスループットを提供します。

Q13. Phi Accrual Failure Detectorが単純タイムアウトより優れている理由は?

単純タイムアウトは固定時間内に応答がなければ障害と判断します。ネットワーク遅延が変動すると誤検知が多くなります。Phi Accrual Failure Detectorはハートビート到着時間の統計的分布を学習し、現在の到着時間が分布からどれだけ逸脱しているか(phi値)で障害確率を計算します。ネットワーク状態の変化に適応的です。

Q14. SagaパターンのChoreographyとOrchestrationの違いは?

Choreographyは各サービスがイベントを発行し、他のサービスがサブスクライブして次のステップを実行します。中央制御がなく結合度が低いですが、フロー追跡が困難です。Orchestrationは中央オーケストレーターが全体フローを制御します。追跡とデバッグが容易ですが、オーケストレーターがSPOFになる可能性があります。

Q15. 分散システムで冪等性(べきとうせい)がなぜ重要ですか?

ネットワーク障害によりリクエストが再送される可能性があるため、同じリクエストを複数回実行しても結果が同一でなければなりません。冪等キー(Idempotency Key)を使用して重複リクエストを検知し、決済や在庫差引のような副作用のある操作で重複処理を防止します。


13. クイズ5選

クイズ1. N=5の分散システムでW=3、R=2の場合、一貫した読取りは保証されますか?

保証されます。 W + R = 3 + 2 = 5 > N(5)なので、書込みセットと読取りセットは必ず重なります。ただしW + R = Nの場合は境界値であり、すべてのノードが正常な時のみ保証されます。

クイズ2. RaftでTerm 5のリーダーがいる時、Term 3のRequestVoteを受信したらどうしますか?

拒否します。 Raftではノードは自身の現在のTermより小さいTermのリクエストを常に拒否します。これにより古いリーダーの干渉を防止します。

クイズ3. Vector Clock V1=[2,3,1]とV2=[3,2,1]の関係は?

**並行(Concurrent)**イベントです。V1の最初の要素(2)がV2(3)より小さいですが、2番目の要素(3)がV2(2)より大きいです。どちらか一方が完全に大きいか等しくないため比較不可能であり、並行イベントを意味します。

クイズ4. CassandraでONE、QUORUM、ALL一貫性レベルの違いは?
  • ONE:1ノードの応答で十分。最速だが古いデータを読む可能性あり
  • QUORUM:過半数(N/2+1)ノードの応答が必要。バランスの取れた選択
  • ALL:すべてのノードの応答が必要。最も遅いが強い一貫性。1ノードでも障害があれば失敗
クイズ5. 2PCでPrepare後にコーディネーターが障害を起こしたらどうなりますか?

参加者がブロッキングされます。PrepareにYesで応答した参加者はコミットも中止もできず、リソースロック状態で無限待機します。これが2PCの最大の問題点であり、3PCやコーディネーターログ復旧で解決します。


14. 参考資料

書籍

  1. Martin Kleppmann, "Designing Data-Intensive Applications" (2017)
  2. Maarten van Steen, Andrew S. Tanenbaum, "Distributed Systems" (4th ed., 2023)
  3. Mikito Takada, "Distributed Systems for Fun and Profit"(オンライン無料)

論文

  1. Brewer, E., "CAP Twelve Years Later" (IEEE Computer, 2012)
  2. Lamport, L., "The Part-Time Parliament" (1998) — Paxos原論文
  3. Ongaro, D. & Ousterhout, J., "In Search of an Understandable Consensus Algorithm" (2014) — Raft論文
  4. Lamport, L., "Time, Clocks, and the Ordering of Events in a Distributed System" (1978)
  5. DeCandia, G. et al., "Dynamo: Amazon's Highly Available Key-value Store" (2007)
  6. Corbett, J.C. et al., "Spanner: Google's Globally-Distributed Database" (2012)

Web資料

  1. Jepsen — 分散システム安全性テスト: https://jepsen.io/
  2. Raft Consensus Algorithm可視化: https://raft.github.io/
  3. Aphyrの分散システム講義: https://github.com/aphyr/distsys-class
  4. AWS re:Invent分散システム発表シリーズ
  5. Martin Kleppmannブログ: https://martin.kleppmann.com/
  6. Marc Brookerブログ: https://brooker.co.za/blog/
  7. Distributed Systems Reading Group: http://dsrg.pdos.csail.mit.edu/