分母を変えれば可用性は変わる
一言でいうと
SLIはクエリではなく定義です。何を良いイベントとして数え、何を有効なイベントとして数えるかを決めることが、数字の大部分を決めます。
なぜ必要なのか
障害対応の会議で最もよく出る一言は、「うちの可用性は何パーセントだったのか」です。ところが同じ12時間のデータを前に、3人がそれぞれ98.9%、97.7%、97.2%を持ってきます。3人とも計算は合っています。違う質問に答えていただけです。
1人目は、5xxの応答だけを失敗として数えました。2人目は、400番台の応答も失敗として数えました。3人目はリクエストではなく分を数えました。1分のあいだにエラー率が基準を超えたら、その1分をまるごと悪い分として見たのです。
この違いは言葉遊びではなく、お金と人の時間がかかる違いです。定義が緩いとエラーバジェットが残っているように見えて危険なデプロイが通り、定義が厳しすぎると何も起きていない夜に人が起こされます。そのため、目標(SLO)を何パーセントにするかよりも先に、何を数えるかを合意しなければなりません。
どう動くのか
Google SRE Workbookは、SLIを1文で表します。有効なイベントのうち良いイベントの割合、です。そのため定義を書くときは、3つの項目を埋める必要があります。
| 項目 | 決めること | よくある間違い |
|---|---|---|
| イベント(event) | 何を1つと数えるか | リクエストと時間ウィンドウを混ぜて使います |
| 良いイベント(good) | 何を成功と見なすか | ステータスコードだけを見て、遅い成功を成功として数えます |
| 有効なイベント(valid) | 何を分母に入れるか | ヘルスチェック・ボット・内部呼び出しまで分母に入れます |
3つの項目のうち1つを変えるだけでも、数字が変わります。特に分母が怖いのです。1秒に6回動くヘルスチェックを分母に入れると、ユーザーが体験する失敗がヘルスチェックの成功に薄められ、障害が小数点以下に押しやられます。逆に、分母をユーザージャーニー1つに絞ると、同じ事故がずっと大きく見えます。
イベントの単位をリクエストから時間に変えると、性質そのものが変わります。リクエスト基準は、トラフィックの多い時間帯の事故により大きなペナルティを与えます。時間基準は、午前2時の20分の障害と午後2時の20分の障害を、同じ20分として数えます。どちらが正しいかは、サービスがユーザーに何を約束したかで決まります。
レイテンシを成功の条件に入れるときは、ヒストグラムの限界を知っておく必要があります。リクエスト数のカウンターにはステータスコードのラベルがありますが、レイテンシのヒストグラムにはたいていありません。すると「200で、かつ100ミリ秒以内に終わったリクエスト」を1つのクエリで数えられません。2つのシグナルを掛け合わせて使うには、メトリクスをそのように出力するよう計装を直さなければなりません。定義が計装を決める瞬間です。
測定する場所も、定義の一部です。同じリクエストを、アプリケーションの中で測るか、前段のプロキシで測るか、ブラウザで測るかによって、数字が変わります。アプリケーションの中で測ると、接続が切れて応答がユーザーに届かなかったケースが成功として残り、プロキシで測ると、プロキシ自身が死んでいた時間が記録からまるごと消えます。どの場所で測るにせよ、その場所が見ることのできない失敗が何かを併せて書いておいて初めて、あとで数字を信じられます。
期間をどう区切るかも決める必要があります。暦の基準(毎月1日にバジェットがリセットされる)は契約書に書きやすい反面、月末に駆け込みで危険なデプロイをするように仕向けます。ローリングウィンドウ(直近30日)は、そうした駆け込みを防ぐ代わりに、過去の事故が1か月間ついて回ります。どちらも正しいという選択があるわけではなく、どちらがチームの行動を望む方向に変えるかで選びます。
最後に、SLIを複数作って1つに平均しないでください。可用性とレイテンシと正確性は、それぞれ別の約束なので、平均を取ると、どの約束も守っていないのに数字だけ良く見える状態ができあがります。それぞれを別々に測り、それぞれに目標を設定し、それぞれのバジェットを別々に消費させるほうが、はるかに扱いやすくなります。複数のSLIを1つの数字にまとめたいという要求は、たいてい報告書を短くしたいという意味ですが、その要求を聞き入れた瞬間、どの約束が破られたのか誰にもわからなくなります。
現場での姿
決済サービスで、こんなことが一度ありました。ダッシュボードの可用性は99.9%を超えているのに、顧客からの問い合わせが入り続けていました。分母に内部のバッチ呼び出しが入っていて、その呼び出しが全体の半分を占めていたのです。ユーザーリクエストだけに分母を絞ると、同じ時間の可用性は99.2%に下がりました。数字が悪くなったのではなく、そこで初めて正しい数字が出たのです。
逆方向の事故もよくあります。あるチームは「遅いのも失敗」という原則を立て、しきい値を100ミリ秒にしました。その瞬間、可用性は85%に落ち込み、エラーバジェットが毎朝使い切られて、デプロイが永遠に止まりました。しきい値がユーザーの体感ではなく、担当者の好みから出たからです。定義を変えるときは、その定義で過去30日を測り直し、その数字で運用していけるかをまず確認しなければなりません。
次のラボですること
Podの中のPrometheusにある12時間分のデータで、4つのSLIを自分で計算します。リクエスト基準で5xxだけを失敗として数え、400番台まで失敗として数え、レイテンシ100ミリ秒を成功の条件に入れ、最後に1分のウィンドウをイベントとして数えてみます。4つの数字がどれだけ開くかを見て、30日間の許容ダウンタイムに換算したあと、1つを選んで機械が読める形式で宣言し、2つの目標でデプロイを許可するか止めるかを判断します。