方針の出発点はすでに定義されたSLIだ

SLOを作りダッシュボードに99.x%を出しても、リリースの基準が生まれるわけではありません。実際の物差しになるには、どの利用者の結果を測るか、どの水準を目標とするか、どの期間を評価するか、エラーバジェットをどれだけ使ったときにどの種類の変更を制限するか、誰が例外を承認するかまでを、一つの運用ポリシーとして合意する必要があります。Google SREもこの点をはっきり分けます。[2] 組織がエラーバジェットを実際の意思決定と業務の優先順位に使うと合意しなければ、SLOはもう一つの報告用の数字にとどまります。

目標値から決めると順序が逆になります。まず重要な利用者導線を定義し、成功と失敗をどのイベントで判断するかを決める必要があります。方針がその前の段階から受け取るべき入力は八つです。

ここに条件がもう一つ付きます。SLI自体を信じられない状態では、エラーバジェットもリリースの物差しになりません。計測が途切れたのにこれを100%正常として扱ったり、実際の要求の相当部分が分母から消えている状態なら、エラーバジェットが十分に残っているという計算にも意味がありません。ですから方針には、バジェットの状態だけでなく、測定を信じられるかどうかの状態も必要です。

重要な利用者導線
ポリシーで必要な理由: どの利用者の結果を守るのかを固定する
成功イベントと有効イベント
ポリシーで必要な理由: 目標値とエラーバジェットの分子と分母を定める
除外規則
ポリシーで必要な理由: 利用者の取消や不正な要求をサービスの失敗と混同しない
測定地点
ポリシーで必要な理由: 実際の利用者体験と測定値の距離を知る
計測の網羅の証跡
ポリシーで必要な理由: 計測の欠落を正常と読み違えない
重要な利用者区分
ポリシーで必要な理由: 全体平均が特定の集団の失敗を隠していないか確かめる
結果不明の要求の扱い
ポリシーで必要な理由: 結果の分からない要求を勝手に成功として数えない
配備バージョンとの結び付け
ポリシーで必要な理由: バジェットの消費と特定の変更との関係を調べられるようにする

99.9%から書き始めない

目標値はサービスの等級を飾る数字ではありません。Google SREは三つの条件をともに求めます。[2] プロダクト側は、それ以下の性能なら利用者のためにエンジニアリングの時間を使う価値があると同意する必要があります。開発側は、バジェットを使い切ったら実際に行動を変えると合意する必要があります。運用の責任者は、過度な労苦や消耗なしにその目標を守れる必要があります。

したがって99.9%を既定値に置いて理由を後から付ける進め方は避けるほうがよいでしょう。目標値を決めるときは、少なくとも六つの問いに答える必要があります。この利用者導線がどの程度失敗すると実際の利用者が問題を感じるか、金銭やデータ、権限、業務の停止のように失敗の費用が大きい導線か、いまの指標はどの程度で、その測定値を信じられるか、通常の運用条件でこの目標を保てるか、より高い目標のために増える費用と運用の複雑さが利用者に実際の価値を与えるか、いまの目標が緩すぎて、相当な利用者被害が出た後にしか方針が働かないのではないか、です。

最初から完璧な数字を探す必要もありません。Google SREは初期の目標を測り、繰り返し直していく進め方を勧めます。[2] いま達成できないより高い目標が必要なら、それは志向目標として別に追い、エラーバジェットポリシーを即座に発動させる運用目標と区別します。つまり目標値には、数字だけでなく、なぜこの数字なのかという根拠が付く必要があります。

サービスの仕組み

監視から復旧・改善までつながる運用 — サービス指標とアラートを基準に対応し、変更履歴と事後報告を次の改善につなげます。

評価の期間も方針の一部だ

同じ目標値でも、どの期間を見るかによって決定は変わります。Google SREは移動窓とカレンダー整列の窓を区別します。[2] 移動窓は、月末に起きた障害が翌月一日になったという理由だけで利用者の体験から消えるわけではないという点で、利用者体験とよく合います。カレンダーの窓は、四半期ごとの人員や計画のように、組織の計画周期と結び付けやすいものです。

Googleは四週間の移動窓を汎用的な出発点として紹介しますが、これを標準の期間として強制しません。短い窓は素早い運用の調整に、長い窓は大きな信頼性投資の判断により適すると説明します。したがって方針には、窓の種類と長さ、配備と変更の判断に使う運用の検討周期、信頼性投資の優先度を見る長期の検討周期、そしてこの窓が利用者体験と業務の周期に合う理由を併せて記録します。

28日と30日、一か月は似て見えても、常に同じ意味ではありません。平日と週末のトラフィックが大きく違ったり、月末に業務が集まるサービスなら、窓を選ぶこと自体が指標の結果を変えます。

エラーバジェットは常に「許容ダウンタイム何分」ではない

エラーバジェットの基本の考えは単純です。1から目標値を引いた値がバジェットです。しかし実際の消費の単位は、指標の計算方式によって変わります。

有効な要求200,000件に対する成功率の目標が99.5%なら、その期間に許される失敗イベントは1,000件です。許容される失敗イベントは、有効イベントに1から目標値を引いた値を掛けて求めます。バジェットの消費率は、実際の失敗イベントを許容される失敗イベントで割って求めます。この場合エラーバジェットは、ダウンタイムの分数ではなく失敗したイベントの数を中心に読みます。一方、時間を一定の区間に分けて各区間を成功か失敗かで判定する目標なら、失敗した時間の切れ端がバジェットを消費します。

現在のクラウド事業者の文書も、要求ベースの指標と時間窓ベースの指標を区別します。OpenSLO v1はバジェットの算定方式を、発生件数、時間の切れ端、比率による時間の切れ端として明示的に分けます。[1] 方針テンプレートには目標値だけでなく、バジェットの算定方式と消費の計算式まで記録する必要があります。とくにトラフィック量によって分母が変わる要求ベースの目標を運用の途中で評価するなら、今回の期間の最終的なエラーバジェットが正確に何件かはまだ確定していないことがあります。カレンダーの窓で将来の要求量が分からない場合、途中時点の判断にはこうした不確かさがあるとGoogle SREも指摘します。[2]

残りの予算より、いまどの政策状態かを定める

ダッシュボードにはいくつもの数字があります。目標の遵守率、許容されたエラーバジェット、使ったバジェット、残ったバジェット、直近の消費量、消費の速さです。問題はこの数字が行動へ変わらないときです。運用の方針では、数字を四つの政策状態へ移すほうが扱いやすくなります。

CONSTRAINEDへ移る正確な数値を、すべての組織に同じように当てる理由はありません。チームが必要なら、残りのバジェットの比率、期間の終了前に使い切る可能性、一定規模の単一の事象といった条件を定めればよいでしょう。ただしその値は、インターネットのテンプレートから持ってくるより、そのサービスの配備の頻度やトラフィックの型、失敗の被害、対応の力に合わせるべきです。

バジェットの消費をどの速さで計算し、いつ呼び出しやチケット、ダッシュボードへ届けるかは通知設計の問題です。ここでは方針がどの状態を必要とするかまでを定めます。

政策状態
意味
既定の運用姿勢
NORMAL合意した範囲でバジェットが十分にある既存のリリース方針に従って変更する
CONSTRAINED余裕が減ったか、現在の消費の傾きが危ういリスクの大きい変更を減らし、証跡と承認の水準を上げる
EXHAUSTEDその期間のエラーバジェットを使い切った信頼性が回復するまで、追加のリスクを生む変更を既定で制限する
MEASUREMENT_UNTRUSTEDSLIの網羅やデータ品質の問題でバジェットを信じられない自動で許さず、手動の判断か保守的な変更方針を当てる
政策状態 — 数字を行動へ変える四つの状態

バジェットを使い切っても、すべての配備が同じリスクではない

エラーバジェットの方針で最も危うい単純化は、バジェットがあれば配備でき、なければすべての配備を禁じるという一行です。実際の変更には、それぞれ違う目的と違うリスクがあります。バジェットの状態と変更の種類を組み合わせるほうが現実的です。

この表の目的は、すべての会社が同じように運用せよということではありません。定めるべきは、バジェットが減るほどどの種類のリスクを受け入れなくするかです。Googleの例示のエラーバジェットポリシーも、使い切ったときに機能の変更を制限しつつ、最優先の等級とセキュリティの修正を例外に置きます。[3] さらに、依存が原因の目標未達をどう扱うかについても、内部のリリースを続けるという考えと、追加の事故を防ぐため変更凍結を当てるという考えの両方がありうるので、サービスに合う選択を方針に記録するよう説明します。

EXHAUSTEDは「何も触らない」ではなく、追加の利用者リスクを生む変更の既定の許容水準が下がった状態として読むほうが正確です。実際の変更を一時停止、フラグ切り、トラフィックの回収、ロールバック、前進修正のどれで行うかは別の問題であり、コード・設定・DB・データ・機能露出・トラフィックをともに扱うロールバック設計がその実行の契約を担います。

変更の種類
NORMAL
CONSTRAINED
EXHAUSTED
新機能・実験通常のリリース方針影響範囲の縮小、追加の検討、または延期既定で制限
定例の設定・基盤の変更通常どおり進める必要性と変更リスクを再検討緊急でなければ延期
高リスクのDB・データ変更別の高リスク変更方針原則として保守的に適用既定で制限
信頼性の改善通常どおり進める優先度を上げる必要なら優先して実施
セキュリティ・緊急の修正リスクに応じて進める遅延のリスクと変更のリスクを比べるあらかじめ定めた例外・承認の手順で実施
障害の緩和・ロールバック必要なら実施必要なら実施サービス回復のため実施
バジェット状態 × 変更の種類 — バジェットが減るほどどのリスクを受け入れないかを決める

信頼性の作業も方針に書く

機能の凍結だけを書いて「その間に安定化する」と記せば、実際の業務の優先順位はなお曖昧なままです。バジェットが速く消費されたり使い切られたときに、どの信頼性作業を始めるかも定義する必要があります。

たとえば八つです。エラーバジェットを最も多く消費した失敗の種類の分析、繰り返す信頼性の不具合の修正、危うい依存の緩和、テストや配備の検証の強化、復旧時間を縮める自動化、容量と資源の飽和の解消、誤って定義された指標やイベント分類の修正、繰り返し例外を求めさせる構造的な原因の除去です。Google SREも、エラーバジェットを信頼性プロジェクトの優先順位に使えると説明します。[2] 同じ人員を投じるなら、実際のバジェット消費をより大きく減らす作業を先に選べばよいのです。

ここでも「使い切ったらチーム全体が信頼性作業だけを行う」といった値を汎用の規則にする必要はありません。方針が定めるべきは、引き金と信頼性作業の優先度の変更、担当者、完了すべき最小の条件、そして政策状態から抜ける終了条件です。移動窓なら、時間が経つにつれ過去の失敗が窓の外へ出てバジェットが自然に回復することもあります。数字が正常の範囲へ戻ったという理由だけですべての制限を自動で解けば、原因はそのまま残ります。重大な未達では、バジェットの回復とともに再発のリスクを減らす措置が行われたかを終了条件に置くとよいでしょう。[3]

例外は障害の後に交渉しない

エラーバジェットの方針が最も必要になるのは、当初の計画と現実がぶつかるときです。バジェットはないが直ちに当てるべきセキュリティ修正があるかもしれません。現在の版の障害を緩めるための配備が要るかもしれず、データの損失を防ぐために新しい変更を入れる必要があるかもしれません。このとき毎回「今回だけ配備してよいか」を一から議論すれば、方針は意思決定の費用を減らせません。

例外を多く許すことが目的ではありません。逆に例外が繰り返し必要なら、既存の目標値や変更の方針が実際の運用と合っていないという合図です。その場合は例外を足し続けるより、方針そのものを見直す必要があります。

項目
記録する内容
例外の候補どの状況が例外の候補か
要求者誰が例外を求めたか
理由なぜ現在の方針をそのまま当てるとより大きなリスクが生じるか
利用者への影響遅らせた場合に利用者が受ける被害
変更のリスク変更そのものが加えるリスク
緩和策影響範囲と失敗の影響を抑える方法
承認者誰が最終の上書き権限を持つか
有効期限例外がいつまで有効か
証跡承認の時点で使ったデータ
事後の検討結果と追加のバジェット消費をいつ検討するか
例外方針に記録する十項目 — 障害の後に一から議論しないために

SLOの責任者を一人決めるだけでは足りない

エラーバジェットは開発チームと運用チームの間の数字ではありません。Google SREは、プロダクトマネージャーと開発チーム、運用の責任者が方針にともに同意する必要があると説明し、SLOの文書には作成者と検討者、承認者、次の検討日を残すよう勧めます。[2] 方針の適用に意見の相違が生じたときのための上位移管の経路も要ります。実務では責任を六つの役割に分けられます。

小さなチームでは一人が複数の役割を担っても構いません。重要なのは肩書きの数ではなく、誰が数字を計算し、誰が配備を制限でき、誰が例外を承認するかが曖昧でないことです。

サービス・製品の責任者
サービスと製品の責任者は、利用者の被害と事業の要求を基準に目標値の妥当性を承認します。
SLOの責任者
SLOの責任者は、SLIと目標値、評価期間、バジェット計算の定義とデータの信頼性を保ちます。
エンジニアリング・変更の責任者
エンジニアリングと変更の責任者は、実際の変更方針を当て、制限の状態を実行します。
信頼性作業の責任者
信頼性作業の責任者は、バジェット消費の原因と信頼性作業の優先度を管理します。
例外の承認者
例外の承認者は、方針の上書きを承認し、その理由を記録します。
上位移管の責任者
上位移管の責任者は、バジェットの計算や方針の適用に意見の相違があるとき、最終の判断を下します。

検討の周期もあらかじめ定める

サービスは変わります。トラフィックの構成が変わり、顧客が変わり、依存が入れ替わり、以前は重要でなかった利用者導線が中核の機能になることもあります。SLOを一度承認した後、何年もそのまま使えば、最初は妥当だった目標も後には誤った運用の物差しになります。

Google SREは、SLOの運用を始めたばかりのころは月単位のように比較的よく検討し、適合が確かめられた後は四半期単位やより長い周期へ縮められると説明します。[2] 近年のSLOを見直す議論も、複雑なサービスではSLOを広く当てすぎず、どの問いに答えるためのSLOかを絞って定義するよう指摘します。サービスの振る舞いとワークロードが変われば検証を続ける必要があるという意味です。

カレンダーの検討のほかに、事象に基づく検討の条件も置くとよいでしょう。重要な利用者導線が変わった、指標のイベントや測定地点が変わった、主要な依存が入れ替わった、利用者・テナント・リージョンの構成に大きな変化が生じた、配備の頻度や変更のモデルが変わった、方針の例外が繰り返し発生した、SLOは満たすのに利用者の信頼性への不満が続く、SLOを繰り返し外すのに利用者への影響がほとんどない、です。最後の二つがとくに重要です。SLOが実際の利用者体験との相関を失ったなら、目標値を締めるだけでなく指標そのものを見直す必要があります。

方針テンプレートは何を持つか

テンプレートの数字は組織が自ら埋めます。99.9%や30日、特定のバジェットの閾値を既定値として入れません。テンプレートは大きく八つのブロックに分かれます。

政策識別、SLI入力、SLO目標・Window、Budget計算を表の各Fieldへ記入します。

政策状態、変更別許可・制限、Reliability Work、例外・責任・検討も同じ様式へ記入します。事象別検討条件と質問は原文の全項目を個別に残しています。

このテンプレートで自動化の道具が担える部分は多くあります。指標の計算とバジェットの消費、変更ゲートとの連動、承認の記録は仕組みへ移せます。しかし仕組みが自ら決められない値もあります。どの水準の失敗が利用者に受け入れられないか、バジェットが足りないときにどのリスクをあきらめるか、セキュリティ修正を遅らせることと配備することのどちらがより危ういかは、組織のサービス責任と製品の判断が必要です。

Fieldパス
記入値・許可値
policy.name""
policy.service""
policy.critical_user_journey""
policy.scope""
policy.statusdraft | active | suspended
policy.authors[]
policy.reviewers[]
policy.approvers[]
policy.approved_at""
policy.next_review_at""
sli_input.specification""
sli_input.good_event""
sli_input.valid_event""
sli_input.bad_event""
sli_input.excluded_event.definition""
sli_input.excluded_event.rationale""
sli_input.unknown_event_policy""
sli_input.measurement_point""
sli_input.minimum_measurement_coverage""
sli_input.critical_segments[]
sli_input.deployment_version_correlation""
slo.target""
slo.target_rationale""
slo.typeoperational | aspirational
slo.window.typerolling | calendar_aligned
slo.window.duration""
slo.window.rationale""
budgeting_method.typeoccurrences | timeslices | ratio_timeslices
budgeting_method.calculation""
error_budget.allowed_budget_calculation""
error_budget.consumption_calculation""
error_budget.data_source""
error_budget.dashboard_or_report""
policy_states.NORMAL.trigger""
policy_states.NORMAL.exit_condition""
policy_states.CONSTRAINED.trigger""
policy_states.CONSTRAINED.exit_condition""
policy_states.EXHAUSTED.trigger""
policy_states.EXHAUSTED.exit_condition""
policy_states.MEASUREMENT_UNTRUSTED.trigger""
policy_states.MEASUREMENT_UNTRUSTED.fallback_decision_rule""
policy_states.MEASUREMENT_UNTRUSTED.exit_condition""
change_policy.feature_or_experiment.NORMAL""
change_policy.feature_or_experiment.CONSTRAINED""
change_policy.feature_or_experiment.EXHAUSTED""
change_policy.routine_config_or_infrastructure.NORMAL""
change_policy.routine_config_or_infrastructure.CONSTRAINED""
change_policy.routine_config_or_infrastructure.EXHAUSTED""
change_policy.database_or_data_change.NORMAL""
change_policy.database_or_data_change.CONSTRAINED""
change_policy.database_or_data_change.EXHAUSTED""
change_policy.reliability_fix.NORMAL""
change_policy.reliability_fix.CONSTRAINED""
change_policy.reliability_fix.EXHAUSTED""
change_policy.security_or_emergency_fix.NORMAL""
change_policy.security_or_emergency_fix.CONSTRAINED""
change_policy.security_or_emergency_fix.EXHAUSTED""
change_policy.incident_mitigation_or_rollback.NORMAL""
change_policy.incident_mitigation_or_rollback.CONSTRAINED""
change_policy.incident_mitigation_or_rollback.EXHAUSTED""
reliability_work.activation_rule""
reliability_work.prioritization_rule["", ""]
reliability_work.required_outputs[""]
reliability_work.owner""
reliability_work.exit_criteria[""]
exception_policy.eligible_cases[""]
exception_policy.requester""
exception_policy.required_evidence[""]
exception_policy.approval_authority""
exception_policy.escalation_authority""
exception_policy.expiry_rule""
exception_policy.post_change_review""
exception_policy.audit_location""
ownership.service_or_product_owner""
ownership.slo_owner""
ownership.change_policy_owner""
ownership.reliability_work_owner""
ownership.exception_approver""
ownership.escalation_owner""
review.regular_cadence""
review.event_driven_triggers[0]user_journey_changed
review.event_driven_triggers[1]sli_definition_changed
review.event_driven_triggers[2]measurement_coverage_changed
review.event_driven_triggers[3]dependency_changed
review.event_driven_triggers[4]traffic_or_customer_mix_changed
review.event_driven_triggers[5]repeated_policy_exception
review.event_driven_triggers[6]material_slo_miss
review.event_driven_triggers[7]user_feedback_conflicts_with_slo
review.review_questions[0]このSLIは今もユーザーのReliabilityを説明するか。
review.review_questions[1]Targetは実際のユーザー被害に合うか。
review.review_questions[2]Windowは運用・Planningの判断に適切か。
review.review_questions[3]Budget Stateは実際の業務優先度を変えているか。
review.review_questions[4]制限Changeと許可Changeの区分は適切だったか。
review.review_questions[5]Exceptionが通常経路より頻繁に使われていないか。
review.review_questions[6]Policy適用が過剰なToilやリスクを生んでいないか。
SLO & Error Budget Policy Template:原文のField別記入様式

測定と決定と実行を三つの文書に分ける

信頼性の運用を一つの文書ですべて解こうとすると境界がぼやけます。前段の指標設計は利用者導線からSLIを作り、目標値と評価期間、エラーバジェット、配備の方針を次の段階へ渡します。この記事はその入力から、目標値と窓、エラーバジェット、バジェットの消費、政策状態、リリースと変更の方針、信頼性の作業と例外、責任者を決めます。

その次の問題はまた分かれます。バジェットの消費をいつ人へ知らせるべきかは通知の設計です。障害が起きたときにログ・指標・トレース・プロファイルのどれから見るかは信号の選択です。検知と緩和、復旧、連絡は障害対応のランブックが所有します。そして方針が一時停止やロールバック、トラフィックの回収を求めたとき、それを実際に安全に行える構造はロールバック設計の問題です。

SLOとエラーバジェットが実際の物差しになったかは、ダッシュボードの数で判断できません。バジェットが減ったときにチームの行動が変わり、その行動があらかじめ合意されている必要があります。リスクを減らす変更とリスクを加える変更を分けて見て、例外と責任まで記録できなければなりません。バジェットが何の決定も変えないなら、SLOは報告用の数字に近いものです。逆にバジェットが減ったという理由だけですべての変更を等しく止めるなら、方針は粗すぎます。実際の運用の物差しはその間にあります。利用者へ約束した信頼性と、いま残るエラーバジェット、変更が加えるリスク、そしてその決定に責任を持つ人を、一つの方針でつなぐことです。