TL

因果順序とhappened-before関係の図解

分散イベントの「先後」を時空間図で一目で読み解けるようになる。横線と斜めの矢印からhappened-before・並行・ベクタークロックの増分を機械的に判定する手順を、原理から身につけられます。

応用因果順序happened-before分散システムベクタークロック時空間図最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.時空間図(space-time diagram)は、各プロセスを横線、ローカルイベントを点、メッセージを斜めの矢印で描く。因果順序を「線と矢印をたどれるか」という幾何で表す。
  • 2.図上で a から b へ右向きに到達できれば a→b(因果あり)。どちらからも到達できないペアが並行(concurrent)で、これが分散系に固有の状態。
  • 3.ベクタークロックは図の各点に配列を貼る操作で、ローカルイベントは自分の要素を+1、受信は要素ごとmaxして+1。図と数値が1対1で対応する。

時空間図とは何を描くものか

分散システム(/devops/microservices/)で複数プロセスが動くとき、「どのイベントがどのイベントより前か」は壁時計では決められない。そこで因果関係そのものを図にしたのが 時空間図(space-time diagram) である。Lamport が 1978 年の論文で導入した描き方で、論理時計(/devops/logical-clocks/)の議論はほぼすべてこの図の上で行われる。

描き方は単純だ。各プロセスを1本の 横線 で表し、左から右へ時間が進む。線上に打つ がそのプロセス内のイベント(ローカルイベント)。プロセス間で送るメッセージは、送信点から受信点へ向かう 斜めの矢印 で描く。矢印が必ず右上がり/右下がりに「右へ」進むのは、送信より受信が後だからだ。

時間 →
P1: --a----b---------e----->
          \         /
           \       /
P2: --------c-----d-------->

この図で a, b, e は P1 のイベント、c, d は P2 のイベント。b → c の矢印は「b で送ったメッセージを c で受信」、d → e は「d で送って e で受信」を表す。図はこれだけで因果のすべてを含んでいる。

図から happened-before を読む

happened-before 関係(記号 →)は「a は b に影響を与ええた」という因果の可能性を表す。図の上では、次の幾何的な操作にそのまま対応する。

図の読み方は1つだけ

a の点から、横線(右方向のみ)と矢印(送信から受信の向きのみ)だけをたどって b の点へ到達できるなら a → b。逆向き・左向きには進めない。到達経路があるかどうか、それが因果の有無そのものである。

happened-before の3条件は、この「到達可能性」を分解したものにすぎない。

  1. 同一プロセス内:同じ横線上で a が b より左なら a → b(線を右へたどる)。
  2. メッセージ:送信点 a から受信点 b へは矢印で到達できるので a → b
  3. 推移律:到達経路をつなげられるなら a → c。横線と矢印を乗り継いだ経路がこれにあたる。

先の図で確かめる。a → b は同一線上。b → c は矢印。c → d は P2 の線上。d → e は矢印。これらを乗り継げば a → e も成り立つ(a から右へ b、矢印で c、右へ d、矢印で e)。図の上で1本の経路として描けることが、推移律の正体である。

並行イベント:図のどこにも経路がないペア

ここが時空間図の最大の効用だ。a → b でも b → a でもないペア、つまり どちらからも相手に到達できない 2点が存在する。これを 並行(concurrent、記号 a ∥ b) と呼ぶ。次の図を見る。

時間 →
P1: --a-------x---------->
          \
           \
P2: --------b----y------->

a → b(矢印で到達)は成り立つ。では xy はどうか。x は P1 上で a の右、y は P2 上で b の右にある。x から y へは、x が送信点でない限り横線でも矢印でも到達できない。y から x へも同様だ。よって x ∥ y = 並行である。

並行は「矛盾」ではなく分散系の本質

x と y のどちらが「本当に先」かを問うことには意味がない。互いに情報が届いていない以上、観測者ごとに見える順序が変わってよい。並行ペアが存在するからこそ、happened-before は全順序ではなく 半順序(partial order) になる。図に「到達経路のない2点」が必ず現れることが、その視覚的な証拠だ。

裸の波括弧を避けて集合で書くと、あるイベント e に対し「e に到達できる点の集合」{e より前の因果} と「e から到達できる点の集合」{e より後の因果} 以外の、図上のすべての点が e と並行になる。因果の「光円錐」の外側、と言い換えてもよい。

ベクタークロックの増分を図に貼る

時空間図の各点に ベクタークロック を書き込むと、到達可能性という幾何が、配列の大小という数値に翻訳される。N プロセスの系で各点に長さ N の配列を割り当てる。更新規則は次の通り。

# プロセス i の現在値を V_i(初期は全要素 0)とする
# 1) ローカルイベント: 自分の要素だけ +1
V_i[i] = V_i[i] + 1

# 2) 送信: 上で +1 した後の V_i を配列ごとメッセージに添付して送る
# 3) 受信: 要素ごとに max を取り、最後に自分の要素を +1
for k in 0..N-1:
    V_i[k] = max(V_i[k], msg.V[k])
V_i[i] = V_i[i] + 1

先の {P1, P2} の図(2要素配列、左が P1・右が P2)に実際に貼ってみる。

時間 →
P1: --a(1,0)----b(2,0)---------e(3,2)-->
                   \           /
                    \         /
P2: ----------------c(2,1)--d(2,2)------>

たどり方を1点ずつ確認する。a は P1 の最初のローカルイベントで (1,0)b も P1 のローカルイベント(ここで送信)で (2,0)c は b からのメッセージ受信なので、自分の値 (0,0) と受信値 (2,0) を要素ごと max して (2,0)、最後に自分(P2=右)を +1 して (2,1)d は P2 のローカルイベント(送信)で右を +1、(2,2)e は d の受信で、自分 (2,0) と受信 (2,2) の max が (2,2)、自分(P1=左)を +1 して (3,2)

矢印をまたぐたびに相手側の要素が「伝播」して増えるのが、図の上で見て取れる。これが「因果の鎖に沿って情報が伝わる」ことの数値的な現れである。

比較規則:図の到達可能性と完全に一致する

2つの配列 VAVB を次のように比較する。波括弧の集合表記はインラインコードで {すべての k} のように書く。

VA ≤ VB  ⇔  すべての k で VA[k] ≤ VB[k]
VA < VB  ⇔  VA ≤ VB かつ ある k で VA[k] < VB[k]

この数値判定が、図でたどった到達可能性と過不足なく一致する。

図での状態ベクタークロック条件判定
a から b へ経路ありVA < VBa → b(因果あり)
b から a へ経路ありVB < VAb → a(因果あり・逆)
どちらにも経路なしVA ≮ VB かつ VB ≮ VAa ∥ b(並行)
同一の点VA = VB同じイベント

並行の数値シグネチャを上の図で確かめる。b = (2,0)c = (2,1) なら b < c で因果あり(矢印どおり)。一方、もし P2 に b より前の独立イベント c0 = (0,1) があれば、a = (1,0)c0 = (0,1) は1要素目が a で大きく2要素目が c0 で大きいので、どちら向きにも < が立たない。これが「図に到達経路がない」ことの数式版である。

試験・面接での要点

「Lamport タイムスタンプは並行を判定できないが、ベクタークロックはできる」と問われたら、理由は時空間図で言える。Lamport 値は整数1つなので2点に必ず大小がつくが、ベクタークロックは「ある要素で勝ち別の要素で負ける」状態を表現でき、それが図上の到達経路の不在に対応するから、と答える。

図を使う実務上の意味

時空間図は黒板の道具に見えて、実務の判断基準そのものになる。整合性モデル(/devops/consistency-models/)の因果整合性(causal consistency)は「happened-before を保って見せる」契約であり、その happened-before はこの図で定義される。Dynamo 系 KVS が競合バージョンを兄弟(sibling)として残すのも、ベクタークロックが並行(図に経路なし)を検出したときだけだ。

合意アルゴリズム(/devops/consensus-family-tree/)が全順序を作るのは、いわば「並行ペアに人為的な順序を後付けする」操作にあたる。半順序である図の上に、矛盾しない1本の全順序線を引けることを保証するのが合意の仕事、と捉えると位置づけが明確になる。

まとめ

  • 時空間図は各プロセスを横線、ローカルイベントを点、メッセージを斜めの矢印で描く。因果順序を「右向きの線と矢印をたどれるか」という到達可能性 に翻訳する。
  • a から b へ経路があれば a → b、どちらからも到達できなければ a ∥ b(並行)。並行ペアの存在が、happened-before が半順序であることの視覚的証拠である。
  • 各点にベクタークロックを貼ると、ローカルイベントは自分の要素を +1、受信は要素ごと max して +1 という規則で図と数値が1対1に対応する。矢印をまたぐと相手側要素が伝播する。
  • 比較規則 VA < VB は図の到達可能性と完全一致し、どちらにも < が立たない状態が並行=図の経路不在を表す。この対応が因果分析の確かな足場になる。

DevOps/インフラ Article

因果順序とhappened-before関係の図解を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

因果順序

比較で見る軸

難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 5

導入後に効く点

図上で a から b へ右向きに到達できれば a→b(因果あり)。どちらからも到達できないペアが並行(concurrent)で、これが分散系に固有の状態。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
DevOps/インフラ
タグ数
5

判断チェックリスト

  • 自社の用途が「因果順序 / happened-before」に近いか確認する。
  • 強みである「時空間図(space-time diagram)は、各プロセスを横線、ローカルイベントを点、メッセージを斜めの矢印で描く。因果順序を「線と矢印をたどれるか」という幾何で表す。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

因果順序happened-before分散システムベクタークロック時空間図因果順序happened-before分散システム