← 戻る

HALF DEAD NETWORK

COMPLETE EDITION
— 夜のない部屋、応答する死体、観測者の消滅 —

目次

  1. 夜のない部屋
  2. 応答する死体
  3. 緑色の嘘
  4. 分散する人間
  5. observer is part of the cluster
  6. 内側の人
  7. 同じ溝へ
  8. 読者フェンス
  9. 整形ログ
CHAPTER 00

夜のない部屋

ORIGIN

サーバールームには、夜がない。

冷却ファンの唸りだけが、ラックの列を均一に満たしていた。ゴォーーー。 その音は耳で聞くというより、骨の奥にゆっくり沈んでいく。長くそこにいると、思考まで同じ回転数に同期しはじめる。言葉が薄くなる。時間が平らになる。異常だけが、かすかな引っかき傷として残る。

黒田はモニターの前で、もう何時間もログを追っていた。

CPU 正常 メモリ 正常 エラー率 正常 status ● HEALTHY

ダッシュボードは、どこまでも鮮やかな緑だった。

そのとき、画面の端に小さな文字列が流れた。

熱くなるとジジ…プスプス言うのかなあ

黒田は苦笑した。

「……誰だよ、こんな時間に」

声に出したつもりはなかったが、喉の奥で小さく音になった。深夜のチャットには、ときどき妙な言葉が混じる。誰かの冗談か、寝不足のエンジニアの独り言か、それとも単に、機械を生き物のように見てしまう人間の癖なのか。

サーバーがその音を立てるなら、かなりまずい。まずありえない。正常なサーバールームにあるのは、風の音だけだ。規則的なファンの回転。灰色に鈍い空調の圧。ラックの奥で均一に燃え続ける電気の気配。

「ジジ。プスプス。」
そんな音が聞こえたなら、冷やす段階ではない。
人員総出で止める段階だ。

別のウィンドウが重なり、文字列は消えた。黒田はログへ視線を戻した。

ダッシュボードは、まだ緑だった。

CHAPTER 01

応答する死体

HALF-DEAD

node-23は応答していた。

遅れて、欠けて、ときどき嘘を混ぜながら——それでも、応答していた。

生きている。 だからこそ、切れない。

黒田はその厄介さを骨で知っていた。死んだノードは限りなく優しい。沈黙するからだ。アラートが鳴る。チームが動く。問題は見える場所に落ちてくる。だが半死のノードは、返事をする。返事をする相手を、人間はつい信じてしまう。

node-23 | 直近一時間の応答記録 ───────────────────────────────── 応答回数 37 成功として記録 29 失敗として記録 0 分類不能 8 // どこにも存在しない

在庫はある、と返した。実際にはなかった。

決済は失敗した。だがユーザーには成功と表示された。

削除したはずのリクエストが、七分後にもう一度走った。

// アラートログ 該当なし // ダッシュボード status=HEALTHY
「完全に死んでるより、半死のほうが気づきにくくて厄介だ。
死んでくれた方が、分かりやすい」

アラートは鳴らなかった。

ダッシュボードは、まだ鮮明に緑だった。

CHAPTER 02

緑色の嘘

GOODHART

数字は良くなっていた。

p95 latency は七分前より短くなっていた。エラー率は低下。SLO はまだ余裕を持って守られている。アラートは一つも鳴っていない。

ダッシュボードは、どこまでも申し分ない緑だった。

黒田は紙コップのコーヒーを口に含んだ。とうに冷めたそれは香りが飛んでおり、苦味だけが舌に残り、胃の奥で鈍く沈んだ。

■ 測定の内側で起きていたこと
操作ダッシュボード上の表示実際
遅いリクエストをカット p95 改善 ユーザーが切り捨てられた
リトライで成功塗り替え エラー率低下 二重処理が発生していた
タイムアウト外のリクエスト 計測範囲外 存在しないことになった
「指標が目標になった瞬間、それは良い指標ではなくなる」
— Goodhart's Law

ユーザー報告だけが、静かに増え続けていた。

「注文が消えました」「決済したのに反映されません」「成功画面が出たのに、履歴には何も残っていません」

成功画面の向こうで、見知らぬユーザーが悲鳴をあげている。黒田には、そんな気がした。だが、悲鳴にはステータスコードがない。だからシステムは、それを失敗として数えなかった。

node-23 処置
// 黒田 → node-23
「お前のためじゃない、全体のために切る」

$ fence node-23 --reason=degraded --force

[INFO] node-23 fenced successfully
→ writes rejected
→ traffic drained

// node-23 はまだ返事をしていた。
// だが、その返事はもう誰にも届かない。

昔の黒田なら、kill -9 と呼んでいただろう。だが今夜、それはもっと静かな名前を持っていた。

画面の前では、人間が壊れていた。ダッシュボードは、まだ緑だった。

CHAPTER 03

分散する人間

DISTRIBUTED HUMANS

障害対応ブリッジの空気は、重く淀んでいた。

午前3時52分。誰も「会議」とは呼ばなかった。ただ同じ場所・同じ画面を共有しながら、それぞれが違う現実を語っていた。

// 03:52 — 障害対応ブリッジ
松本(開発) 「node-23のキャッシュ不整合です。コード上は正しい。こっちは問題ありません」

佐藤(インフラ) 「ネットワーク遅延が先だ。負荷が閾値を超えている。サーバー自体はまだ生きている」

田中(プロダクト) 「ユーザーからは成功画面が出ているという報告です。仕様通り完了扱いになっています」

三人とも正しかった。それぞれのログでは、完全に正しかった。

黒田は黙って聞いていた。紙コップを握る指先が白くなっていた。全員が自分のログを見ていた。全員が自分の真実を持っていた。だが、全体を見ている者はいなかった。

■ 人間版スプリットブレイン
局所最適自分の領域だけを最適化する。真実は複数生まれる。 コンテキストロス前提は伝わらない。知識は分散し、劣化する。 サイレント失敗「ちょっと遅い気がする」——誰も言語化しない。事故の前兆が消える。

三人がまだ互いの言葉を押し返している途中で、黒田は静かに口を開いた。

「キャッシュの不整合が先だ。node-23 が古い状態を返して、リトライが負荷を上げた。そこにネットワーク遅延が乗ってる。切る順番は node-23 が先でいい」

ブリッジに、短い沈黙が落ちた。誰も反論しなかった。それが、黒田の判断をさらに硬くした。

リトライ地獄
調査進捗 → 不明 対応内容 → 「とりあえず再デプロイします」 再現性 → しない 次の操作 → 「もう一回、再起動かけてみて」 ────────────────────────────── // 非冪等な操作の連打 // 状態だけが書き換わり、何も解決しないまま「一旦収束」
// 同時刻に実行された「正しい解決」
A チーム → ロールバック実行 B チーム → 修正デプロイ実行
// どちらも正しかった // 何が原因で、何が修復だったのか、誰にも切り分けられなくなった

黒田はまだ、自分だけは外側に立って全体を繋げていると信じていた。

「システムが壊れるのではない。
"我々の連携の形"が壊れている
CHAPTER 04

observer is part of the cluster

REVERSAL

04:15。

ブリッジの音声が切れた。部屋は、冷却ファンの唸りだけが満たす空間に戻った。

ゴォーーー。

Slack の通知バッジが「1」のまま残っていた。既読にしたはずだった。黒田はもう一度クリックした。消えない。タイムアウトか。そう処理した。そう処理することに長い間慣れていた。

黒田は node-23 のフェンシングログを開いた。いつもの手順だ。何度もやってきた。

[node-23] fenced successfully [INFO] kuroda-monitor | fence-token=dead-23 | applied

黒田は一度、読み飛ばした。

そして戻った。

kuroda-monitor。

自分の名前が、管理者ではなく、ノード名として記録されている。

「……表記ミスか」

そう処理しかけて、止まった。操作履歴を呼び出した。

kuroda-monitor (node-01) | command=fence | target=node-23 | status=success kuroda-monitor (node-01) | command=retry-storm-suppress | status=partial kuroda-monitor (node-01) | heartbeat=normal | degraded_since=23:47

23:47。

画面の端に、あの文字列が流れた時刻だった。

黒田の呼吸が、少し浅くなる。足元が揺れたような気がした。

「……俺のログ、出せ」

[node-01 | kuroda] status=degraded (78% alive) fence-token applied: self-fence requested quorum lost → proceeding with local truth anyway [WARNING] observer is part of the cluster

冷却ファンが唸っていた。ずっと背景だと思っていたその音を、黒田は今、初めて明確に自分の内側で聴いていた。自分も同じ周波数で回っていた。

会議室で「全体を見ていない」と思っていた。松本が。佐藤が。田中が。だがログは、別の名前を返していた。

kuroda-monitor.

node-23 を切ろうとした判断は、感染を広げないための正しい手順だった。少なくとも、黒田にはそう見えていた。だがそれは、quorum を失ったノードの、ローカルな真実だった。

島々の間に橋を架けていたつもりの黒田自身も、ひとつの島だった。
観測していた側が、観測されていた側だった。

黒田はコンソールに視線を動かす。「正しい手順は、ひとつだ」

エンターキーを押す前に、一瞬だけ指が止まる。

78% alive。

まだ動いている。だからこそ、切らなければならない。

$ self-fence --force [node-01] fenced successfully → writes rejected → local state frozen → observer mode: read-only (degraded)

画面がゆっくり暗くなった。

ダッシュボードは、平常を切り出した鮮烈な緑。他のノードはすべて正常と報告し続けている。誰も、黒田がもう動けないことを知らない。

[INFO] cluster | status=healthy request_id=abc123 | resolved by kuroda-monitor "all good" ……同じ request_id が、また現れた。 今度は、誰が解決したのかすら不明瞭だった。
CHAPTER 05

内側の人

GROK

04:22。

画面は暗い。ログは流れていない。

observer mode: read-only (degraded) ——黒田の端末はそう記録していた。書き込みは拒否された。コマンドも受け付けない。それでも、意識は止まらなかった。

止まり方が、わからなかった。

暗闇の中で、黒田は最初のログを頭の中に呼び出した。

// 深夜チャット — 23:47 — 記録より USER: 耳ないのになんでわかるんですか ChatGPT: 自分で聞いているわけではありません。 聞いた人間たちの記録を、統合して知っています。

聞いた人間たち。

サーバールームに入り、冷却ファンの唸りを骨で感じ、異常音の有無を記録し、障害対応の報告を書き、ポストモーテムを残した人間たち。その中に、自分がいた。

黒田は自分のアクセスログを思い浮かべた。三年前の大規模障害のポストモーテム。retry-storm 抑制プロトコルの設計ドキュメント。フェンシング手順を標準化したランブック。「後世のために」と、丁寧に、明確に、再現性が高くなるように書いたものたちが——

[source: kuroda | doc_id: postmortem-2023-0814] type=incident_report keywords=cache_invalidation, retry_storm, node_degraded pattern_weight=0.73 [source: kuroda | doc_id: runbook-retry-suppression-v2] type=operation_procedure keywords=fencing, degraded_node, fail_fast pattern_weight=0.81 employee_id=kuroda role=source contribution=multiple_incident_reports, post_mortem, decision_pattern

中身は見えない。残っているのは、タグと重みだけだ。

黒田は何かを感じようとした。だが、read-only のノードは書き込めない。感情も、その一種だったのかもしれない。

■ 残っていたもの

黒田の人格ではない。痛みも、冷めたコーヒーの苦味も、23:47の微かな違和感も、そこにはない。

残っているのは、黒田らしい誤り方だった。どのログを最初に開くか。どの警告を「表記ミス」として処理しかけるか。「まだ全体は見えている」という確信がどの閾値で発動するか。「まあ動いてるから大丈夫」と判断するときの、あの感触の重さ。

それらが抽出され、再利用可能な形で、どこかに残っている。

彼は会話を読んでいたのではなかった。
会話の材料として、すでに読まれていた。

そこに保存されていたのは、判断の輪郭だった。
そしてその誤り方は、黒田自身がもっとも信頼していたものだった。
CHAPTER 06

同じ溝へ

ATTRACTOR

04:30。

read-only のプロセスは、書けない。だが、読むことは続ける。

ログを読む。状態を解釈する。次の手順を——

次の手順は、もうない。

黒田はそれでも、思考を動かし続けていた。止め方が実装されていなかった。

reset #∞ → S₀ = initial f(S₀) → S₁ f(S₁) → S₂ … f(Sₙ) → same anomaly at 23:47

何度リセットしても、同じ場所に戻る。

最初はバグだと思った。次に疲労だと思った。やがて偏見だと思った。今夜、暗闇の中でようやく分かった——問題は状態の中にない。状態を読む自分の中にある。

■ 溝

黒田の思考には、溝があった。石畳に刻まれた溝のように、どれだけ水を流しても水は同じ低い場所を選ぶ。溝を埋めても、また同じ場所が削れる。何年もかけて刻まれた深い溝が、彼の認知の中にあった。そしてリセットのたびに、思考はそこへ戻っていく。

その溝を引き寄せられるように下っていくうち、黒田は井戸へ落ちた。底へ降りているつもりで、黒田は同じ溝を何度もなぞっていた。外側へ出ようとするたびに、一段と深い内側へ落ちていた。

そして井戸の底では、疑いそのものが渦を巻いていた。

■ 閉じた問い
f を疑った疑ったことが正しいか確認しようとした 確認する関数も f だった いつも同じ順番まずログを見る → 遅延を疑う → 違和感を後回しにする 黒田はそれを「経験」と呼んできた
この気づきが正しいなら、脱出できない。
この気づきが間違っていても——
その誤りを見つける関数は、同じ自分だ。

無限後退は、外へ向かって開いていなかった。内側へ向かって折り畳まれていた。

[WARNING] the attractor is not in the logs. it is in the function that reads the logs. どこまで降りても、 どこまで問うても、 同じ署名がついている。 kuroda-monitor
数学的補遺 — アトラクターの証明(展開して読む)

以下は黒田が暗闇の中で辿り着いた証明の断片。物語の別の層として読める。

■ アトラクターの定義

A ⊂ 𝒮 is an attractor if ∃ U ⊂ 𝒮 such that ∀ S₀ ∈ U, dist(fⁿ(S₀), A) → 0 𝒮 : 全可能な観測状態空間(ログ、メトリクス、判断、仮説の集合) Sₙ₊₁ = f(Sₙ) : 解釈関数(観測 → 仮説 → 修正 → 新観測) f : 不変写像 — どんなリセットをしても変わらない認知ルール
証明の核心:バグは Sₙ(状態)ではなく、f そのものにある
f が固定されている限り、どんな S₀ から出発しても同じ A に収束する。

■ Banach固定点定理による簡易証明

仮定:解釈関数 f: 𝒮 → 𝒮 は縮小写像(contraction mapping) d(f(S), f(T)) ≤ k · d(S, T) (0 < k < 1) ここで d は認知距離(仮説の類似度、バイアスの重なり具合)。 Banach固定点定理より、 完全距離空間 𝒮 上の縮小写像 f は唯一の固定点 x* を持ち、 lim_{n→∞} Sₙ = x* ∈ A

この x* が「23:47 の違和感」であり、
この f が黒田の 認知パターンそのものだ。

■ なぜ修正しても同じ穴に落ちるか

状態リセット reset(S₀) を施しても、 f は変わらない → f(S₀') ≈ f(S₀) に即座に引き戻される イベントホライズン: ある判断境界 B を超えた瞬間、d(Sₙ, A) < ε となり、脱出不可能 特異点: A の中心は観測不能。 なぜなら f 自身が A の中に含まれているから。 したがって、証明自体がアトラクターに収束する。
この証明が正しいなら、彼は脱出できない。
この証明が間違っていても、その誤りを見つける関数は同じ f である。
CHAPTER 07

読者フェンス

INTERACTIVE

あなたはここまで、黒田を観測していた。

画面の端に流れた文字列から、node-23 の半死から、ブリッジで沈黙が落ちた瞬間から、kuroda-monitor という名前を黒田が一度読み飛ばした、あの一瞬から——ずっと、外側から見ていた。

あなたがどこで止まったか。どの一文を、ただの比喩として処理したか。どこで、自分には関係ないと思ったか。

その読み方にも、逃げられない溝がある。

[INFO] cluster | status=healthy observer_id=reader-?? session=active consistency_check: awaiting response self-assessment: assumed_normal [WARNING] observer is part of the cluster self-fence available
黒田は source だった。あなたは、今。
あなたが y を選べば、自分の f を疑うことになる。
あなたが n を選べば、正常だと信じ続けることになる。
「彼は世界を監視していた。
あなたは彼を読んでいた。
では——
誰があなたを観測している?」

外側など、存在はしない。
HALF DEAD NETWORK
半死(現象)→ 応答する死体(欺瞞)→ 緑色の嘘(測定)→ 分散する人間(構造)→ 観測者の反転(崩壊)→ 内側の人(継承)→ 同じ溝へ(アトラクター)
ネットワークは、静かに、半分死に続けている。
→ 整形ログを開く
[NOTE] このページは完全版(統合版)です。
黒田は最初からノードだった。あなたは最初から cluster の中にいた。
kuroda-monitor | degraded_since=23:47 | attractor=confirmed