Dev Study
← 分散システムの土台
レッスン 4 / 13·約 9 分·第12期 分散システムの土台

「落ちている」とは言えない — タイムアウトは証拠ではなく推測

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け今ここ
  5. Nginx受け口
  6. アプリ処理
  7. DB保存

第30週『死活監視 — 壊れた実体を外す仕組み』では値をどう決めるかを見ました。今回は、値をどう決めても区別できない範囲があることを扱います。

まず結論

タイムアウトが示すのは「決めた時間内に返事が来なかった」ことだけです。相手が落ちているのか、生きていて遅いだけなのか、経路でパケットが消えているのかは区別できません。

これは設定値の選び方が下手だという話ではありません。Google SRE Book は、ハートビートのようなアドホックな手段ではこの種の問題を正しく解けないと明記しています。

? 読む前に予測

2秒でタイムアウトする設定で問い合わせ、応答がありませんでした。相手の状態について何が言えますか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

無言は、相手の状態を運ばない

第30週『死活監視 — 壊れた実体を外す仕組み』では、何回失敗したら外すかという値の決め方を見ました。今回はその手前にある性質を扱います。

観測できるのは「決めた時間内に返事が届いたかどうか」だけで、届かなかったとき、その沈黙には理由が書かれていません。Google SRE Book は、分断のように見えるものの正体をこう並べています。

Network partitions are particularly challenging—a problem that appears to be caused by a full partition may instead be the result of:

  • A very slow network
  • Some, but not all, messages being dropped
  • Throttle occurring in one direction, but not the other direction

そして、タイムアウトでこれを解くこと自体を否定します。

Leader election is a reformulation of the distributed asynchronous consensus problem, which cannot be solved correctly by using heartbeats.

前提は遅延に上限がないこと、すなわち potentially unbounded delays in message passing です。上限がないので、まだ来ない信号と永遠に来ない信号を有限時間で分けられません。

同じ「返事が来ない」に何が対応するか
相手が停止プロセスが消えた
相手が遅い処理中・GC・ディスク待ち
経路で消失パケットが黙って落ちる
観測側に届く形は同じ
返事が来ない3つのどれかは分からない
返ってきた場合だけ別れる
明示的な拒否接続拒否などの返事が届く = 区別できる
  • 上3つは観測側から同じ形にしか見えない
  • 沈黙の理由は沈黙には含まれない
具体実物

同じ形に見える、を実測で見る

3つの相手に同じ curl -m 2 を投げた生出力です。macOS Darwin 25.5.0 / Docker 28.4.0 上の python:3.12-slim(curl 8.14.1)で各ケース1回ずつ実行しました。

3つの相手への curl -m 2(2026-09-17T23:38:41Z / 各1回)コマンド出力
--- ケースA: 生きているが遅いサーバ(5秒後に必ず200を返す) ---
curl: (28) Operation timed out after 2005 milliseconds with 0 bytes received
exit=28 http_code=000 time_total=2.005610
 
--- ケースB: 誰もいないポート ---
curl: (7) Failed to connect to 127.0.0.1 port 8082 after 0 ms: Could not connect to server
exit=7 http_code=000 time_total=0.000060
 
--- ケースC: パケットが黙って消える宛先(10.255.255.1) ---
curl: (28) Connection timed out after 2001 milliseconds
exit=28 http_code=000 time_total=2.001719
 
--- ケースAの相手に -m 10 で問い合わせ直す ---
{"alive":true,"note":"I was never down. I was slow."}
exit=0 http_code=200 time_total=5.759700

A と C は観測が一致しています。しかし A のサーバは一度も停止しておらず、10秒待てば 200 を返しました。B だけが 0.00006 秒で別の形になったのは、接続が明示的に拒否されたからです。

このとき A のサーバ側には次の記録が残りました。

ケースAのサーバ自身のログ(抜粋。トレースバック本体は以下略)コマンド出力
[slow] request received, sleeping 5.0s then answering
[slow] "GET / HTTP/1.1" 200 -
...
BrokenPipeError: [Errno 32] Broken pipe

サーバは5秒かけて処理を終え、応答を書こうとしたときにはクライアントがもういませんでした。クライアントは失敗と記録し、サーバでは処理が完了しています。この食い違いは本コース後半のリトライと冪等の回で扱います。

✓ ここまでの確認

実測で、3つのうち1つだけ区別がつきました。その理由は何でしたか。

抽象原理

値を詰めても、区別は生まれない

区別できないのは値の選び方が悪いからではなく、観測が「届いたかどうか」しか与えないからです。つまみを回して得られるのは区別ではなく誤りの配分です。etcd 公式の Tuning にはこの配分が書かれています。

If heartbeat interval is too low, etcd will send unnecessary messages that increase the usage of CPU and network resources. On the other side, a too high heartbeat interval leads to high election timeout. Higher election timeout takes longer time to detect a leader failure.

同じページの別の箇所には、揺らぎを吸収するためにわざと遅らせる規定があります。

Election timeouts must be at least 10 times the round-trip time so it can account for variance in the network.

既定値は同じ Time parameters 節の、隣り合う2つの段落にあります。Heartbeat Interval の説明の末尾に By default, etcd uses a 100ms heartbeat interval.、Election Timeout の説明の末尾に By default, etcd uses a 1000ms election timeout. とあります。

では疑いを数値で扱えば解けるのでしょうか。Akka 公式の φ accrual 故障検知器は、ハートビートの到着間隔の履歴から次を計算します。

phi = -log10(1 - F(timeSinceLastHeartbeat))

この設計の要点は精度ではありません。

An accrual failure detector decouples monitoring and interpretation. [...] Rather than only answering "yes" or "no" to the question "is the node down?" it returns a phi value representing the likelihood that the node is down.

監視(集める)と解釈(落ちたと決める)を分けているだけです。どの phi で落ちたと決めるかは呼び出し側が選びます。 不可能性が解けたのではなく、二値の判断が呼び出し側へ移されています。

具体実物

誰が「落ちている」と言っているのか

Apache Cassandra は各ノードがこの種の検知器を走らせます。公式の Dynamo ページにはこうあります。

Gossip forms the basis of ring membership, but the failure detector ultimately makes decisions about if nodes are UP or DOWN. Every node in Cassandra runs a variant of the Phi Accrual Failure Detector, in which every node is constantly making an independent decision of if their peer nodes are available or not.

同じページの別の記述が、本レッスンの題名そのものです。

UP and DOWN state are local node decisions and are not propagated with gossip.

gossip が運ぶのはハートビートの状態であって判定ではありません。「あのノードは落ちている」は、そう判定した1台のローカルな意見です。

SRE Book の STONITH の事例は、この意見の食い違いが事故になる形です。ネットワークが遅くなるかパケットを落とし始めたとき、ファイルサーバ群は互いのハートビートのタイムアウトを超え、設計通り相手を落としに行きます。

File server pairs may now be in a state in which both nodes are expected to be active for the same resource, or where both are down because both issued and received STONITH commands.

両方が生きているとも、両方が落ちているとも転びます。 誤検知は片側だけに現れるとは限りません。

SRE Book は、こうした問題は形式的に正しさが証明された分散合意アルゴリズムだけで解くべきだとし、Ad hoc means of solving these sorts of problems (such as heartbeats and gossip protocols) will always have reliability problems in practice. と述べています。

✓ ここまでの確認

φ accrual 故障検知器について、Akka 公式の記述に沿った理解はどれですか。

⇄ 2つを見比べる
具体例 A

タイムアウトによる生死の判定

返事が来ないという観測には、相手の停止・遅延・経路での消失が対応します。区別できないまま落ちたと決め、切り離しや引き継ぎを行います。判定は1台のローカルな意見にとどまります。

実測での観測(2026-09-17 / 各1回)表
相手の実際の状態 exit http_code time_total
生きているが遅い 28 000 2.005610
パケットが消える 28 000 2.001719
誰もいない(拒否) 7 000 0.000060
具体例 B

第23週『届いたことを確かめる — ACKと再送、そして規定と実装のズレ』

ACKが返らない観測にも、データの消失・ACKの消失・相手の遅延が対応します。TCPは区別せず一律に再送し、RFC 6298 の手順 (5.5) は再送タイマ満了のたびに RTO を倍にすることを求めています。

RFC 6298 の手順 (5.5) の規定表
場面 規定 要件語
再送タイマ満了 RTO <- RTO * 2 MUST

同じ「返事が来ない」なのに、TCPの再送は日常的に安全で、生死の判定は事故になります。この差はどこから来るのでしょうか。

区別できない性質は両方に共通します。違うのは、区別しないまま取った行動の後始末を誰が引き受けているかです。

この章のまとめ

  • タイムアウトが言えるのは「決めた時間内に返事が届かなかった」ことだけで、相手の状態は含まれない。
  • 実測では、生きていて遅いサーバとパケットが消える宛先が exit=28 / http_code=000 / 約2秒 で一致した。区別できたのは明示的に拒否された1件だけ。
  • 値を詰めても区別は生まれず、誤りの配分が変わる。遅延の原因は相手のネットワークとも限らない(etcd 公式は他プロセスのディスク遅延で一時的にリーダーを失うと書いている)。
  • φ accrual は監視と解釈を分離し phi を返すだけで、二値の判断は呼び出し側に残る。Cassandra の UP / DOWN は ローカルな決定であってクラスタの合意ではない。
  • 設計の重心は、判定を正確にすることより、誤判定が起きても壊れない行動を選ぶことに置く。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 3正解: 0

「タイムアウトを短くすれば故障を早く検知できる」の評価はどれですか。

用語集(3語)
非同期モデル (asynchronous)
メッセージ配送の遅延に上限を置かない前提。Google SRE Book は potentially unbounded delays in message passing と表現する。上限がないので、まだ来ない信号と永遠に来ない信号を有限時間で分けられない。
FLP 不可能性
プロセスが1台でも停止しうる非同期系では、どの合意プロトコルにも決着しない実行がありうるという結果(原論文の Abstract は even with only one faulty process)。否定されるのは停止性であって安全性ではない。原論文自身が、実務で解けないことを示すものではないと明言している。
φ accrual 故障検知器
ハートビートの到着間隔の履歴から phi = -log10(1 - F(timeSinceLastHeartbeat)) を計算し、二値ではなく疑いの度合いを返す検知器(Akka 公式)。Cassandra も同種の検知器を使う。