影響の見積もり
一行まとめ
「何人が影響を受けたか」は、ログを数える問題ではなくルールを決める問題です。何を除き(ヘルスチェック・ボット・社内)、何を一つに まとめ(リトライ・同じ人の複数セッション)、いつを数えるか(タイムゾーン付きの区間)を決めてはじめて、数字が一つに収束します。
なぜこれが必要だったのか
インシデントが起きると、同じ質問に三つの数字が出てきます。ステータスページチームは「リクエスト4千件が失敗」、カスタマーサポートチームは「ユーザー172人」、 SREチームは「80人」と言います。三つとも同じログから数えており、どれも計算として間違ってはいませんが、ルールが違います。告知に出せるのは一つだけで、 補償・規制当局への報告・SLOの計算はその数字をそのまま使います。大きく書きすぎれば不要な補償と信頼の毀損を招き、小さく書きすぎれば隠蔽になります。
どのように動くのか
第一に、ノイズを除きます。Kubernetesのヘルスチェック(/healthz, /readyz)は障害中にかえって多く失敗し、検索エンジンのボットや社内の 合成モニタリングもユーザーではありません。パス・User-Agent・社内アドレス帯(10.0.0.0/8 など)で見分けます。
第二に、リトライを一つにまとめます。クライアントは失敗すると再試行します。同じリクエストidの行は一つのリクエストで、ユーザーが体験した 結果は最後の試行です。最初の試行が失敗してリトライが成功したなら、そのリクエストは失敗ではありません(遅かっただけです)。行を数えると失敗が 膨らみ、「一度でも失敗」で数えると失敗したユーザーが膨らみます。
第三に、人を数えます。失敗リクエスト数はユーザー数ではありません。一人が何度も失敗します。ログインした人は複数の端末・セッションを 開いても一人で、ログインしていない訪問はセッション一つを一人として数えるしかありません(そのためこの数字は「少なくともこれだけ」に近いものです)。
第四に、区間と分母を決めます。区間はタイムゾーン付きの時刻でやり取りします。「14:10から」をUTCとして読むと、9時間 ずれた区間を数えてしまいます。エラー率は同じルールで数えた失敗 ÷ リクエストで、平常時のエラー率と並べてはじめて意味を持ちます。影響を受けたユーザーも その区間のアクティブユーザーと一緒に書いてこそ、規模が見えます。
最後に、ルールをコードとして残します。手で数えた数字は次のインシデントでまた手で数え直す必要があり、人によってまた変わります。
同じログでルールを一つずつ破ると、数字はこのように分かれます(ラボの素材一式で数えた例)。
| 計算 | 影響を受けたユーザー | 何が間違っていたか |
|---|---|---|
| ルールどおり | 99 | — |
| ヘルスチェック・ボット・社内アドレス帯を残した | 118 | ユーザーではないリクエストが混ざった |
| リトライ中に一度でも失敗すれば失敗とした | 172 | リトライで成功した人まで数えた |
| 失敗リクエスト数をそのまま使った | 117 | 一人の複数の失敗を複数人として数えた |
| 区間の +09:00 を捨てた | 0 | 9時間後を数えた |
数字を一つだけ見ると、どれもおかしく見えないのが怖いところです。そのため告知には、数字と一緒にその数字を出したルール(何を 除き、何をまとめたか)を一行書き添えるチームが多くあります。次の人が同じルールで数え直せるようにするためです。
現場でよく見る光景
三つのチームの数字が違うときにすべきことは、誰が正しいかを争うことではなく、ルールを一行ずつ突き合わせることです。ステータスページのスクリプトは ヘルスチェックを除いておらず、カスタマーサポートのスクリプトはリトライの最初の失敗を失敗として数え、もう一つは区間をUTCとして読んでいました。 こうした違いはスクリプトを同じルールに揃えれば消え、同じ数字が一つ残ります。
ログインしていない訪問には限界があります。同じ人がブラウザを変えるとセッションが二つになって二人と数えられ、逆に共有 端末は複数の人を一人として数えます。そのため匿名の訪問が多いサービスは、「影響を受けたユーザーは最低N人(ログインベースではM人)」のように 二つを分けて書きます。いずれにしても、ルールを隠さないことが要点です。
数字は分母と一緒に読みます。「99人」は、その区間にアクティブだった372人のうちの99人なのか、3万人のうちの99人なのかで、まったく別の インシデントになります。エラー率も平常時のエラー率と並べてこそ規模が見えます。平常時0.4%だったものが9%になったなら20倍で、平常時 8%だったものが9%になったのならインシデントではないかもしれません。SLOを使うチームなら、これらの数字がそのままエラーバジェットの消費量になります。 同じルールで数えたリクエスト・失敗でバジェットを差し引いてこそ、四半期末に「今回のインシデントがバジェットの何%を使ったか」を他のインシデントと比べられます。
最後に、影響の数字はインシデント中に何度も変わります。最初の告知の数字はその時刻までの値で、インシデントが終わった後のポストモーテムの 数字は全区間の値です。両者が違うのは正常で、二つの数字がどちらも同じルールから出ていることさえ守れば十分です。 そのため告知ごとに「何時時点」かを一緒に書きます。基準時刻のない数字は、後で誰が数え直しても突き合わせられません。
次のラボでやること
決済障害のアクセスログからヘルスチェック・ボット・社内トラフィックを取り除き、リトライをまとめてリクエスト・失敗・エラー率を数え、影響を受けたユーザーを ルールどおりに数えます。そのルールをスクリプトにして初めて見るログにも合うかを確かめてもらい、最後に数字が食い違う三つのチームの スクリプトを直します。