良いデバッグは痕跡が残らない
一言でいうと
30分で正確に絞り込んで直した人と、3時間さまよって偶然直した人のコミットは、同じ形をしています。そのため、記録を残さなければ、実力も組織の資産も積み上がりません。
なぜ必要なのか
デバッグが経験年数に比例して伸びない理由は3つあります。
1つ目は、明示的に教える場がほとんどないことです。言語とフレームワークは学びますが、絞り込む手順は見よう見まねで覚えます。
2つ目は、フィードバックのかかり方が間違っていることです。症状が消えると報酬が来ます。なぜ消えたのかわからない状態も、同じように報われます。そのため、運で直した経験が実力と誤認されます。
3つ目は、よいデバッグは痕跡が残らないことです。組織がこの能力を見分けにくく、見分けられなければ育成もされません。
これに対する対応は1つだけです。痕跡を残すことです。
絞り込む手順には名前がある
記録を残すには、まず手順が必要です。経験のある人が無意識にしていることに名前を付けておけば、学べるようになります。
二分探索: リクエストが通るレイヤーを半分に切ります。クライアント → ゲートウェイ → サービス → DBなら、まずゲートウェイから直接サービスを呼んでみます。通れば前のほうが、通らなければ後ろのほうが犯人です。1回で候補が半分になります。レイヤーが8つなら、3回で1つに絞れます。
差分の絞り込み(delta debugging): うまくいくものと、いかないものの両方があるときに使います。うまくいくリクエストといかないリクエストの違いを1つずつ消していき、どの違いが消えた瞬間に症状も消えるかを探します。ヘッダー1つ、フィールド1つ、時刻1つが残ります。
時間軸を揃える: デプロイ・設定変更・トラフィック増加の時刻と、症状の開始時刻を1行に並べます。ほとんどの障害は、何かが変わった直後に始まります。「いつからか」を正確に知ることは、「何が原因か」の半分です。
仮定をひっくり返す: 30分以上絞り込めなかったなら、確実だと信じていたことの1つが間違っている可能性が高いです。「DNSは当然動く」「設定は反映された」「そのバージョンで合っている」。こういうことを、1つずつ実際に確認します。たいていここで見つかります。
記録の形式: 1枚で十分
長く書くと誰も書きません。実務で実際に続いている形式は、このくらいです。
## 증상
결제 완료 화면에서 간헐적 500 (약 20%)
## 재현
for i in $(seq 20); do curl -s -o /dev/null -w '%{http_code}
' -X POST https://stg/api/pay -d @fixtures/pay.json; done
→ 20회 중 4~6회 500
## 배제
- 인증: 401/403 이 로그에 0건
- 네트워크: 같은 요청을 게이트웨이 안에서 직접 → 같은 비율로 실패
- 데이터: 실패한 요청의 body 가 성공한 것과 바이트 단위로 동일
## 원인
결제 서비스 파드 3개 중 1개만 옛 설정(타임아웃 1초)으로 떠 있었다.
ConfigMap 을 바꾼 뒤 rollout restart 를 하지 않아 그 파드만 옛 값을 안고 있었다.
## 수리 전후
전: 20회 중 5회 실패 / 후: 40회 중 0회 실패 (같은 명령)
## 다음에 이걸 막는 것
- [ ] ConfigMap 해시를 파드 애노테이션에 넣어 변경 시 자동 재시작 (담당: 배포팀, 3/25)
このコードブロックの韓国語の見出しは、順に、症状・再現・除外・原因・修理前後・次にこれを防ぐものという意味で、例の内容は、決済完了画面で約20%の割合で断続的に500が出ていて、決済サービスのPod3つのうち1つだけが古い設定(タイムアウト1秒)のまま動いていた、というものです。
「次にこれを防ぐもの」の項目が、この文書の価値です。原因だけが書かれた記録は、同じ障害に2回目に出会ったときに検索できる程度ですが、ここまで書かれた記録は2回目をなくします。
タイムボックスを決めておく
絞り込めないまま時間が過ぎることが、デバッグの最大のコストです。あらかじめ決めておきます。
| 経過 | すること |
|---|---|
| 15分 | これまでに除外したことを文章で書きます。書いている間に、抜けているレイヤーが見えてきます |
| 30分 | 確実だと信じていた仮定の1つを、実際に確認します |
| 45分 | 人を呼びます。説明している途中で、自分で見つけることが半分です |
| 60分 | 迂回路があるかを見ます。原因の究明とサービスの復旧は別のことです |
最後の行が特に重要です。障害対応では、復旧が先で、原因はあとです。ロールバックで5分で復旧できるのに、原因を探して1時間を使うのは、間違った優先順位です。
どう動くのか
FDEが残すべき記録は4種類あります。
再現コマンド: 症状を起こす最小のコマンド1行。これがあれば、修理できたかどうかを同じ物差しで判定でき、なければ「直ったようだ」までしか言えません。
除外リスト: 確認して消したレイヤーと、その根拠。1行で十分です。auth — 401/403 이 로그에 한 건도 없음のように書きます(韓国語の文は「ログに401/403が1件もない」という意味です)。
測定値の前後: 修理前は20回中5回失敗、修理後は20回中0回。2つの数字が同じ方法で測定されたことが重要です。
去ったあとも残る文書: FDEの成功条件は特殊です。自分がいなくても回ることが成功です。常駐が終わる日にシステムも一緒に止まるなら、それはデプロイではなくレンタルだったことになります。
現場での姿
引き継ぎ文書で、顧客が最もよく開き直すのは、アーキテクチャ図ではなく障害ランブックです。よく起きる症状ごとに、最初の30分で何をするかが書かれた文書です。ランブックがないシステムは、引き渡せないシステムです。
そして文書を渡す日には、文書だけを渡さず、顧客のエンジニアがランブックどおりに障害シナリオを1つ自分で処理してみるリハーサルまで行うのが、完結です。読んで理解したことと、手が動くことは違います。
記録の形式より重要なのはタイミングです。引き継ぎ文書は最後の週ではなく、プロジェクトの中盤から積み上げる必要があります。最後の週にまとめて書いた文書は、例外なく「何ができないのか」が抜けています。そのころには本人がすでにその例外に慣れてしまい、特別だと感じないからです。
次のラボですること
4種類を実際に残します。そして最後に、採点ツールが次の人の役を務めます。書いた再現コマンドを、自分のシェルではないきれいな環境でもう一度実行します。そこで同じ数字が出てはじめて、記録が記録と呼べるようになります。