mcpField
O
observability-service-reliability

observability-service-reliability

github.com/elasticクラウド・DevOps6021.1k 回インストール今日更新
リポジトリ

observability-service-reliability について

Elastic のオブザーバビリティツールでサービスの信頼性目標を設計・運用するスキルです。ユーザーに見える課題とデータに応じて手段を選び、Kibana で SLO とバーンレートアラートを管理します。

主な機能

  1. 01SLO・ルール・異常検知ジョブ・シンセティックスの選択
  2. 02指標フィールドと実測履歴の検証
  3. 03SLO の目標・期間・予算方式の設定
  4. 04SLO の作成と管理
  5. 05バーンレートアラートルールの追加

活用シーン

  1. 01ユーザーに見える結果の SLO 定義
  2. 02容量しきい値に対する監視手段の選択
  3. 03SLO へのバーンレートアラート追加
  4. 04シンセティックスによるエンドポイント可用性確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/elastic/agent-skills --skill observability-service-reliability

インストール後、Claude Code で/observability-service-reliabilityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
burn-rate-rules.md
documentation.md
slo-api-schemas.md

詳細

サービス信頼性

実際に人が行動に移せる信頼性目標を設計し、それを運用します。このスキルでは、API 呼び出しの前に必要な判断、つまり、手元のデータに適したサービスレベル指標は何か、実現可能な目標は何か、あるいはそもそも SLO が適切な手段なのかを検討し、その後、Kibana API を通じて SLO を作成し、アラートを設定し、リセットし、廃止する手順を扱います。

信頼性を測る手段は、相互に置き換えられるものではありません。SLO は、ユーザーに見える結果を、消費可能な予算と照らし合わせて測定します。しきい値ルールは、生の条件に対して発火します。異常検知ジョブは、固定のしきい値が存在しない場合に逸脱を検出します。シンセティックモニターは、テレメトリーの送信が完全に止まったサービスを検知できる唯一の手段です。選択を誤ると、技術的には正しくても運用上は役に立たないアラートが発生します。すでに劣化しているサービスの診断とインシデント対応ワークフローについては observability-sre-triage スキルを、一般的なルールのライフサイクル手順については kibana-alerting-rules スキルを使用してください。

環境設定

このスキルは elastic CLI を介して Elasticsearch の操作を実行します。elastic CLI がインストールされていない場合は、何に必要なのかをユーザーに伝えてください。認証情報を推測したり、HTTP API を直接呼び出したり、別の回避策を試したりしないでください。

このスキルでは、HTTP の短縮形式(例:GET /、GET /_cat/indices、GET /{index}/_mapping、GET /{index}/_settings/index.mode、POST /_query)で操作を記載しています。このドキュメント末尾の操作表で、各短縮形式に対応する elastic CLI コマンドを確認できます。HTTP API を直接呼び出すのではなく、必ず CLI を使用してください。

クラスターにアクセスせずに分析する

上記の CLI チェックは、_クラスターへのクエリ実行_を制限するものであり、分析を制限するものではありません。ユーザーが質問に必要な根拠(メトリクス値、件数、ステータスの理由、ログ行、アラートのペイロード、設定)をすでに提示している場合は、その根拠に基づいて判断し、結論を示してください。

ユーザーが提示していないデータが本当に必要な場合は、何をどのように確認するかを伝え、疑問を解決できる具体的なクエリ、インデックス、フィールドを示したうえで、CLI のセットアップを依頼してください。確認内容を明示すればクラスターにアクセスできなくても有用な回答になりますが、セットアップだけを求める回答では不十分です。

SLO とアラートの操作は Kibana に対して実行し、kbn: プレフィックスを使用します(例:POST kbn:/api/observability/slos)。データの検証は Elasticsearch に対して実行し、プレフィックスなしのパスを使用します(例:POST /_query)。Kibana の SLO コマンドではスペースを指定する必要があります。デフォルト以外のスペースでは、HTTP パスは kbn:/s/<space_id>/api/observability/slos になります。

すべての SLI タイプのリクエスト本文スキーマは references/slo-api-schemas.md、バーンレートルールのスキーマは references/burn-rate-rules.md、厳選された公式ドキュメントは references/documentation.md にあります。

実施する作業

  • 信頼性に関する懸念を適切な手段(SLO、バーンレートルール、しきい値ルール、異常検知ジョブ、シンセティックモニター)に結びつける
  • サービスとデータの形状に合った SLI タイプを選択し、確定する前に基盤となるフィールドを検証する
  • 測定した履歴に照らして説明可能な目標、期間、予算設定方式を決定する
  • SLO をグループ化するか判断し、カーディナリティの高いグループ化は拒否する
  • SLO を作成、検証、更新、リセット、無効化、削除する
  • ファストバーンとスローバーンのウィンドウを重大度別に振り分けたバーンレートアラートルールを追加する
  • 重複する監視を取り除き、無効化する代わりにスヌーズし、対応不能なルールを削除して、アラートの監視対象を有用なシグナルに絞る
  • シンセティックテストでユーザー向けエンドポイントの可用性を監視し、その結果を可用性 SLI に反映する

出力に関する規律

このスキルで生成されるすべての応答に適用されます。

  • 最も根拠のある結論を選びます。 SLI 設計を 1 つ推奨し、その根拠を示します。あらゆる種類の SLI を同等に扱って列挙し、選択をユーザーに委ねてはいけません。それは推奨ではなく、選択肢の提示です。
  • 選んだ目標値と期間を、その理由とともに 1 度だけ述べます。 箇条書きごとに根拠を繰り返してはいけません。
  • フィールド名を捏造してはいけません。 インジケーターにフィールドを書き込む前に、マッピングと照合してすべてのフィールドを確認します。確認できないフィールドがある場合は、その旨を伝えて作業を中断します。もっともらしいフィールド名を使うより、確認できないと認めるほうが適切です。
  • 証拠を超えて推測してはいけません。 測定履歴が目標値を裏付けていない場合は、その履歴が裏付ける範囲を述べます。
  • データがない場合は、そのとおりに報告します。 イベントが 0 件の場合、データが欠落しているか、サービスがデータを出力していないことを意味します。サービスが正常であることを意味するものではありません。合計イベント数が 0 件の場合、SLI 比率は 100%ではなく未定義です。
  • 余計な内容を加えてはいけません。 質問を言い換えたり、結果に関係のないクエリの実行内容を説明したりしません。
  • 調査結果で締めくくります。 「設定しておきましょうか?」など、最後に提案を持ちかけてはいけません。実行可能なフォローアップは、質問ではなく推奨事項として、推奨事項の一覧に記載します。

プロセス:信頼性に関する懸念を適切な計測手段に振り分ける

設計を始める前に実施してください。悪い SLO の多くは、しきい値ルールを装ったものです。

  1. ユーザーに見える症状を明確にします。 ユーザーや下流の利用者が何に気づき、何について苦情を申し立てるかを確認します。答えが体験ではなくリソースの数値(ディスク使用率 90%、ヒープの増加、レプリカの遅延など)なら、その懸念は信頼性の目標ではなく、容量の上限です。しきい値ルールに振り分けてください。

  2. すでにカバーされているか確認します。 GET kbn:/api/observability/slos で SLO を、GET kbn:/api/alerting/rules/_find でアラートルールを、GET /_ml/anomaly_detectors で異常検知ジョブを一覧表示します。すでにカバーされているシグナルに計測手段を追加することは、ページ通知が重複する最も一般的な原因です。

  3. 計測手段を選びます。

    懸念計測手段理由とコスト
    数週間にわたって予算管理したい、ユーザーに見える成功率またはレイテンシの結果SLO +バーンレートルール消費可能な予算と履歴が得られ、変更速度を調整できます。トランスフォームのコストがかかり、安定したトラフィックが必要です。また意図的に反応が遅く、急速なバーンでも 1 時間のウィンドウを使用します。
    安全な値が既知で、即時のオペレーター対応が必要な固定上限しきい値ルールまたはカスタムルールトランスフォームなしで、スケジュール間隔以内に発火します。ただし予算も履歴もないため、条件が続く限り再び発火します。
    固定のしきい値がなく、季節性が強い、またはエンティティが多数あるシグナル異常検知ジョブ未知の異常を検出し、季節性に適応します。信頼できる結果を得るには数週間分の履歴が必要です。また、結果ではなくスコアを出力するため、ページ通知には適していません。
    独自のテレメトリの外部から見た、ユーザー向けエンドポイントへの到達可能性シンセティックモニター完全停止を検知できる唯一の計測手段です。チェック予算が必要で(シンセティックスのセクションを参照)、内部の部分的な障害の原因は説明できません。
    利用者との契約がない内部ジョブ、または日々変化しているサービスなしオーナーも安定したベースラインもない SLO は常に赤の状態になり、やがて無視されるようになります。これは SLO がないよりも悪い状態です。
  4. 停止時のケースを省略しないでください。 サービス自身のログやトレースから作成した SLI では、サービスが消失したことを検知できません。イベントがゼロだと total が存在せず、比率が未定義になるため、SLO はバーンも回復もしません。ユーザー向けサービスのリクエストベース SLO には、必ずシンセティックスの可用性モニターか、データなしを検知するしきい値ルールを組み合わせてください。これは 1 つのシグナルに 2 つの計測手段を使うことが重複ではなく、適切となる唯一のケースです。

プロセス:SLO を設計する

  1. データの場所を特定し、フィールドが存在することを確認します。 GET /_resolve/index/<pattern> でインデックスパターンを解決し、次に GET /<index>/_mapping または GET /_field_caps で、インジケーターが参照するすべてのフィールドを確認します。OTel ネイティブのデータは traces-*.otel-*、metrics-*.otel-*、logs-*.otel-* にあり、3つすべてに service.name が設定されています。APM の集計メトリクスは metrics-service_summary.1m.otel-*、metrics-service_transaction.1m.otel-*、metrics-transaction.1m.otel-*、metrics-service_destination.1m.otel-* にあります。慣例的に使われるからといって、ステータスコード、期間、結果のフィールドが存在すると想定しないでください。必ず確認してください。フィールド名を間違えると、SLO は正常に計算されても、意味のない値になります。フィールドが見つからない場合の動作で、具体的な動作を説明しています。

    よく誤って推測されるフィールドの配置が2つあります。http.response.status_code は traces-*.otel-* にあり、logs-*.otel-* にはありません。また、transaction.duration.us は traces-*.otel-* にあり、metrics-*.1m.otel-* のロールアップにはありません。ロールアップには代わりに transaction.duration.histogram と transaction.duration.summary があります。この一覧を鵜呑みにせず、使用する環境で両方を確認してください。

  2. 何も作成する前に、ES|QL で SLI を検証します。 POST /_query で直近の履歴に対する正常数/総数の比率を実行し、測定されたベースラインを確認してください。このクエリは探索用であり、KQL ではなく ES|QL で記述されています。

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 30 day
    | STATS total = COUNT(*), good = COUNT(*) WHERE http.response.status_code < 500
    | EVAL achieved = good::DOUBLE / total
    

    OTel デモクラスターでは、total: 1393887、good: 1393887、achieved: 1.0 が返されます。これは手順4で使う測定済みの入力値であり、そのままコピーする目標値ではありません。30日間のデータが完全に良好であれば、目標は100%未満に設定するのが妥当です。

    HTTP ステータスはログではなくトレースにあります。 http.response.status_code は traces-*.otel-* に設定されています。OTel のログレコードには HTTP ステータスが含まれないため、このフィールドは logs-*.otel-* には存在しません。また、トレース上でのカバレッジはサービスごとに異なり、HTTP サーバーが出力したスパンにのみ設定されます。kind == "Server" でフィルタリングすると、そのサービスが受信したリクエストは対象に残り、他のサービスへの呼び出しのステータスを報告するクライアントスパンは除外されます。このフィールドを使ってインジケーターを作成する前に、対象サービスのカバレッジを確認してください。

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 24 hour
    | STATS spans = COUNT(*), with_status = COUNT(http.response.status_code)
    

    同じクラスターで cart は spans: 46420, with_status: 46420 を返します。一方、gRPC サービスの checkout は spans: 4887, with_status: 0 を返します。with_status が0の場合、予算に使える HTTP ステータスはありません。sli.apm.transactionErrorRate を使うか、プロトコルにかかわらずすべての OTel スパンに設定される event.outcome で比率を作成してください。

    FROM traces-*.otel-*
    | WHERE service.name == "checkout" AND kind == "Server" AND @timestamp >= NOW() - 30 day
    | STATS total = COUNT(*), good = COUNT(*) WHERE event.outcome == "success"
    | EVAL achieved = good::DOUBLE / total
    

    total: 147009、good: 146996、achieved: 0.9999 が返されます。good は否定形(== "failure" ではない)ではなく、肯定形(== "success")で記述してください。null の結果が正常として数えられてはなりません。

    この違いは Serverless 固有のものでも、特定のデモアプリケーションに限ったものでもありません。Stack 9.4.4 クラスター上のすべてのサービスについて、traces-*.otel-* を対象に kind == "Server" で同じ測定を行った結果は次のとおりです。

    サービスサーバースパン数http.response.status_code のカバレッジevent.outcome のカバレッジ
    catalog49,2710%100%
    gateway37,773100%100%
    orders37,754100%100%
    payments34,710100%100%
    recommendations34,6920%100%
    shipping34,531100%100%
    6 つのサービスのうち 2 つには HTTP ステータスがまったくありませんが、6 つすべてで各スパンに event.outcome があります。catalog の http.response.status_code < 500 に基づいて可用性 SLO を作成すると、good: 0、total: 49271 と計算されます。達成 SLI は 0%、エラーバジェットは全量消費され、健全なサービスに対してバーンレートルールが継続的にページ通知を行います。API レスポンスにも SLO UI にも、このことを示すものはありません。分子が常にゼロになるだけです。
    毎回、対象のサービスについて上記のカバレッジチェックを実行してください。また、複数のサービスをカバーする 1 つの指標を作成する場合は、event.outcome を優先してください。

    欠落しているフィールドを、もっともらしく見える別のステータスフィールドで置き換えてはいけません。それによって何が起きるかについては、欠落フィールドによる失敗を参照してください。

    また、比率を意味のあるものにするにはトラフィックが十分に多いことも確認してください。最も少ないバケットのイベント数がわずかしかない場合、1 件の失敗で SLI が何ポイントも変動し、SLO がノイズになってしまいます。

    FROM traces-*.otel-*
    | WHERE service.name == "cart" AND kind == "Server" AND @timestamp >= NOW() - 7 day
    | STATS events = COUNT(*) BY bucket = BUCKET(@timestamp, 1 hour)
    | SORT events ASC
    | LIMIT 10
    

    これには必ず明示的に範囲を指定してください。@timestamp の条件がないと、トレースデータストリームの保持期間全体をバケット化します。デモ用クラスターでは安価でも、顧客のクラスターでは高コストになります。

  3. 好みではなく、データの形状から SLI タイプを選択してください。

    SLI タイプ使用する状況
    sli.kql.customイベントに対するフィルターで good と total を表現できる、生ログやドキュメントの場合
    sli.metric.customgood と total を合計やカウントの式で表現できる、事前集計済みのメトリックフィールドの場合
    sli.metric.timeslicep95 レイテンシの上限など、スライスごとにしきい値と比較するメトリックの場合
    sli.histogram.customgood には範囲、total には値のカウントを使用するヒストグラムフィールドの場合
    sli.apm.transactionDurationミリ秒単位のしきい値に対する APM トランザクションレイテンシの場合
    sli.apm.transactionErrorRateAPM トランザクションの成功率の場合
    sli.synthetics.availabilityユーザー向けエンドポイントの Synthetics モニター稼働時間の場合

    適用できる場合は APM または Synthetics タイプを優先してください。サービス、環境、トランザクションの各ディメンションが自動的に設定され、基盤となるインデックスのレイアウトが変わっても正しく機能します。結果が生イベントでしか確認できない場合は sli.kql.custom を、サービスがすでに独自のカウンターを出力している場合は sli.metric.custom を使用してください。

  4. 達成可能な目標を設定してください。 ステップ 2 で測定したベースラインを基に、目標をその値と同じか、それをわずかに下回る値に設定し、サービスが達成できたら段階的に引き上げます。測定したベースラインを上回る目標を設定すると、初日から予算全量を消費し、SLO は常に赤色のままとなり、チームはそれを見なくなります。objective.target は 0 から 1 までの小数値です。99.5 ではなく 0.995 を指定してください。30 日間でどれだけの予算になるか、目標値を次の表で確認してください。

    目標30 日間のエラーバジェット
    99%7h 12m
    99.5%3h 36m
    99.9%43m 12s
    99.95%21m 36s
    99.99%4m 19s

    単一のローリングデプロイ、ノードの再起動、または 1 回の依存関係の障害で予算全体を超える場合、その目標は達成不可能です。注釈付きで受け入れるのではなく、却下してください。

  5. 時間枠を選択します。 timeWindow.type は rolling(7d、30d、90d)または calendarAligned(1w、1M)です。 ローリングウィンドウは連続的に移動するため、予算は徐々に回復し、バーンレートアラートも有効に機能します。そのため、運用目的のものにはこれがデフォルトです。カレンダーに合わせたウィンドウは期間の境界でリセットされます。契約上の表現や月次レポートには適していますが、月初に予算が急落します。ページングにはローリングを使用し、誰かが実際に暦期間でレポートしている場合に限り、カレンダーに合わせた SLO を併せて追加します。

  6. 予算計算方法を選択します。 occurrences はウィンドウ全体の良好なイベント数を全イベント数で割るため、トラフィックの多い時間帯が大きく影響し、深夜のトラフィックが少ない時間帯の障害はほとんど反映されません。timeslices はウィンドウをスライスに分割し、objective.timesliceTarget に照らして各スライスを良好または不良と判定してから、良好なスライス数を全スライス数で割るため、各期間が等しくカウントされます。トラフィックの少ない期間も重要な場合や、指標がカウント可能な良好/合計ではなく、集計値に対するしきい値である場合は、timeslices を選択します。sli.metric.timeslice には budgetingMethod: "timeslices" が必要です。この組み合わせは任意ではなく、objective.timesliceTarget と objective.timesliceWindow も必須になります。

  7. グループ化は慎重に決めます。 groupBy は一意の値ごとに独立した SLO インスタンスを作成し、それぞれに独自の変換バケットとアラートを設定します。設定する前にカーディナリティを測定してください。

    FROM traces-*.otel-*
    | WHERE @timestamp >= NOW() - 24 hour
    | STATS instances = COUNT_DISTINCT(service.name)
    

    @timestamp の条件は必ず指定してください。時間条件のないカーディナリティ集計は、トレースデータストリームの保持期間全体を対象に実行されます。直近の期間を指定すれば、同じ疑問への答えをはるかに低いコストで得られます。

    確認すべき点はカーディナリティだけではありません。対象のディメンションに値が入力されている必要もあります。マッピング済みでも値が null のフィールドを groupBy に指定すると、すべてを対象とする退化したインスタンスが 1 つ作成されます。グループ化された SLO が機能しているように見えても、実際にはそうではありません。設定する前に COUNT(<field>) と COUNT(*) を併用して確認してください。

    service.name、service.environment、k8s.namespace.name など、安定していて値の範囲が限られたディメンションでグループ化します。trace.id、url.full、user.id や、頻繁に変わる k8s.pod.name などの高カーディナリティフィールドは拒否し、SLO を作成してから警告するのではなく、その理由を説明してください。カーディナリティの大きいディメンションでエンティティごとの可視性が本当に必要な場合は、すべてをグループ化するのではなく、対象となるエンティティに絞り込んでください。Synthetics SLO はモニターとロケーションで自動的にグループ化されます。手動で groupBy を設定しないでください。

  8. 作成して検証します。 references/slo-api-schemas.md に従ってリクエスト本文を作成し、POST kbn:/api/observability/slos を実行します。その後、GET kbn:/api/observability/slos/{id} で読み戻し、成功を報告する前に計算が行われていることを確認してください。作成した SLO でも、変換がまだ開始されていない場合はサマリーデータが返されません。

ここでは KQL はスタイルの選択ではなく、API の契約です

Observability のクエリ言語は ES|QL です。SLI を検証するために実行する探索的クエリ(ベースライン、カーディナリティの確認、トラフィック分布)はすべて、POST /_query に対する ES|QL で記述する必要があります。

例外は SLO リクエスト本文です。sli.kql.custom の good、total、filter フィールド(および他のインジケータータイプの filter フィールドと、SLO 検索の --kql-query パラメーター)は、SLO API がそのように定義しているため、KQL 文字列です。これらのフィールドには ES|QL 形式がありません。ここでのみ KQL を記述してください。

{
  "type": "sli.kql.custom",
  "params": {
    "index": "traces-*.otel-*",
    "filter": "service.name : \"cart\" and kind : \"Server\"",
    "good": "http.response.status_code < 500",
    "total": "*",
    "timestampField": "@timestamp"
  }
}

これらのフィールドを ES|QL に変換しないでください。API が拒否するか、誤って解析する可能性があります。探索的クエリを KQL に変換することも避けてください。

フィールドが存在しない場合の問題

ステップ 1 でフィールドの確認を必須としているのは、2 つの方言では失敗の仕方が正反対であり、危険なのは SLO に組み込まれる方だからです。

探索用の ES|QL クエリは明確に失敗します。http.response.status_code が存在しない logs-*.otel-* をステップ 2 のクエリの対象にすると、HTTP 400 が返されます。

line 3:49: Unknown column [http.response.status_code]

インジケーターの本文内の KQL はまったく失敗しません。 KQL はマッピングされていないフィールドに対する数値比較を、何にも一致しない範囲クエリにコンパイルし、SLO API は何も警告せずに定義を受け入れます。logs-*.otel-* に 101,920,257 件のドキュメントを保持するクラスターで、同じ 1 時間のウィンドウを使うと、good 句に一致したドキュメントは 0 件でしたが、total: "*" には 93,847 件が一致しました。SLO は問題なく計算され、目標に対する SLI が 0% と報告され、最初のトランスフォーム実行でエラーバジェット全体を消費します。次のセクションのバーンレートルールを追加すると、何も測定していないインジケーターで高速バーンのウィンドウが継続的にページを発生させます。

代わりに Lucene の query_string でフィールドを確認しようとしてはいけません。同じ述語を Lucene で使うと、このクラスターでは 3,250 件に一致します。これはフィールドが存在するからではなく、Lucene が式をトークン化し、デフォルトフィールドに対して全文検索でその断片に一致するからです。Lucene で一致件数がゼロでないことは、フィールドがマッピングされている証拠にはなりません。

質問に直接答える GET /_field_caps または GET /<index>/_mapping で確認してください。また、マッピングされたフィールドに実際に値が入っているかどうかもわかる ES|QL の COUNT(<field>) で確認してください。

手順:ノイズを増やさずに SLO のアラートを設定する

SLO を作成しても、アラートは作成されません。バーンレートルールは SLO API によって自動作成されることはなく、POST kbn:/api/alerting/rule/{id} を使って、ルールタイプ slo.rules.burnRate を個別に設定する必要があります。

  1. 重大度の異なる複数のウィンドウを使います。 バーンレートが 1 ということは、ウィンドウの終わりまでにエラーバジェットを使い切るのにちょうど十分な速さで消費していることを意味します。高速バーンのウィンドウ(長いウィンドウが約 1 時間、短いウィンドウが 5 分で、約 14 倍)は、障害を検知するため、ページを発生させる価値があります。低速バーンのウィンドウ(24~72 時間にわたって約 1~3 倍)は、慢性的な性能低下を検知するためのもので、チケットキューに送るのが適切です。すべてのウィンドウを同じページングコネクターにルーティングするのは、SLO が無視されるようになる最も手っ取り早い方法です。ウィンドウの値とアクショングループについては、references/burn-rate-rules.md を参照してください。

  2. 短いウィンドウを維持します。 各ウィンドウは、長いウィンドウ(バーンレートから見てアラートを発生させるべきか)と短いウィンドウ(まだ問題が続いているか)を組み合わせています。インシデントが解決したときに、誰かが手動でミュートしなくてもアラートが自動的に停止するのは、短いウィンドウのおかげです。

  3. 重複する監視を取り除きます。 バーンレートルールと通常のしきい値ルールが同じシグナルを監視していると、1 件のインシデントで 2 回ページが発生します。何かを追加する前に、GET kbn:/api/alerting/rules/_find で重複を確認してください。SLO が構造上検知できないデータ欠損ケースをしきい値がカバーしている場合を除き、バーンレートルールをページング用に残し、通常のしきい値ルールは重要度を下げるか削除してください。その場合は実際の監視上の不足を補うため、そのルールを残すべきです。

  4. 無効化せず、一時停止します。 1 つのルールを期間限定で一時停止するには POST kbn:/api/alerting/rule/{id}/_snooze_schedule を使います。多くのルールに影響する計画済みの変更には、POST kbn:/api/maintenance_window でメンテナンスウィンドウを設定します。どちらも自動的に期限切れになります。ルールを無効化するとアラート履歴が失われ、誰かが再有効化を忘れないことに依存するため、POST kbn:/api/alerting/rule/{id}/_disable は一時的に不都合なルールではなく、誤っているルールにのみ使ってください。

  5. 対応可能性の基準で評価します。 正しく発火しても、対応者が実行できるアクションがないルールは成功ではなく欠陥です。各ルールについて、オンコール担当者が最初に取るべき手順を明確にしてください。正直な答えが「あとで確認する」であれば、それはページではありません。低速バーンのウィンドウかチケットに移すか、削除してください。

プロセス:シンセティックスで可用性を監視する

シンセティックスモニターは、1 つ以上のロケーションからスケジュールに従ってエンドポイントをプローブし、結果を synthetics-* に書き込みます。 これは「外部から見て稼働しているか」という問いに答えるための仕組みです。サービス自体が出力するテレメトリでは、この問いには答えられません。モニターは GET kbn:/api/synthetics/monitors と POST kbn:/api/synthetics/monitors で管理します。

  1. ターゲットを選ぶ前にチェックの予算を見積もります。 可用性はリクエスト数ではなくチェック数で測定されるため、チェック頻度によって SLI の解像度が決まります。30 日間にわたって 10 分間隔でチェックすると、チェック数は 4,320 回です。目標値が 99.99% の場合、エラーバジェットは半回分にも満たないため、一時的な障害が 1 回起きるだけで使い切ってしまいます。少なくとも 10 回分のチェックに相当する予算を確保してください。確保できるまで頻度を上げるか、目標値を下げます。

  2. 少なくとも 3 つのロケーションを使います。 1 つのロケーションだけを使うモニターでは、サービスのダウンと、あるリージョンからのネットワーク経路の障害を区別できません。3 つ以上あれば判断が明確になり、誤ったページ通知を引き起こす要因を一通り排除できます。

  3. SLI に取り込みます。 sli.synthetics.availability を使い、モニター ID、プロジェクト、またはタグで対象を絞って SLO を作成します。インジケーターはモニターとロケーションごとにすでに 1 つのインスタンスを生成するため、groupBy は未設定のままにします。

プロセス:運用と修復

  • 慎重に更新します。 PUT kbn:/api/observability/slos/{id} は、基盤となるトランスフォームをリセットし、履歴を最初から再計算します。目標値やインジケーターを変更すると、既存の予算の状況が破棄されます。実行する前にそのことを伝え、以前の履歴が引き続き重要な場合は、2 つ目の SLO を作成することを優先します。
  • 停止したらリセットします。 POST kbn:/api/observability/slos/{id}/_reset は、トランスフォームとロールアップデータを再構築します。SLO の更新が停止したとき、インデックスのマッピングを変更した後、またはアップグレードによって定義が古くなったときに使います。GET kbn:/api/observability/slos/_definitions で、古くなった定義を確認できます。
  • 一時停止と廃止を使い分けます。 POST kbn:/api/observability/slos/{id}/disable は定義を保持したまま計算を停止し、POST kbn:/api/observability/slos/{id}/enable は計算を再開します。DELETE kbn:/api/observability/slos/{id} は元に戻せません。実行する前に必ずユーザーに確認してください。
  • クラスター構成を確認します。 すべての SLO は継続的なトランスフォームに支えられているため、クラスターには transform ロールと ingest ロールの両方を持つノードが必要です。SLO がいつまでも「no data」のままの場合は、インジケーターのデバッグを始める前に、これを確認してください。

例

「チェックアウトサービスの SLO を設定して」 — traces-*.otel-* を解決し、service.name と outcome フィールドが存在することを確認します。POST /_query で直近 30 日間の成功率を測定し、その後、設計案を 1 つ提案します。測定したベースラインが 99.6% の場合は、occurrences による予算設定を用いて、30 日間のローリングウィンドウで sli.apm.transactionErrorRate を 0.995 に設定する案を提示し、99.9% は、その予算である 43 分がサービスで観測された月間の劣化より短いため却下すると伝えます。SLO を作成して読み戻した後、バーンレートルールを別途作成します。

「Payments API の SLO を 99.99% にしたい」 — まず測定します。直近のベースラインが 99.7% の場合、99.99% はただちに却下します。30 日間の予算は 4 分 19 秒で、1 回のローリングデプロイにも満たないためです。今は 99.5% とラチェット計画を提案し、制約となっているのは目標値ではなくデプロイプロセスだと明記します。

「p95 レイテンシが 500 ms を超えたらアラートを送って」 — これは集計値に対するしきい値なので、パーセンタイル指標を指定した sli.metric.timeslice を使い、comparator: "LT"、threshold: 500 とします。また、この指標で必須の budgetingMethod: "timeslices" を指定し、timesliceTarget と timesliceWindow も設定します。まずマッピングで duration フィールドとその単位を確認してください。ミリ秒単位で記述したしきい値をマイクロ秒単位のフィールドと比較すると、値が 1,000 倍ずれます。

「どの Pod の信頼性が低いか分かるように、Pod ごとに SLO を作成して」 — グループ化は拒否します。k8s.pod.name はデプロイのたびに変わるため、groupBy の値ごとに SLO インスタンスが作成され、数日以内に孤立します。一方、transform にはカーディナリティが永続的に残ります。代わりに k8s.namespace.name または service.name でグループ化することを提案し、Pod ごとの信頼性は予算を設定する目標ではなく、調査すべき症状だと指摘します。

「ログノードのディスクがどんどんいっぱいになるんだけど、これを SLO にできる?」 — できません。ディスク使用率は、安全な上限が明確で、オペレーターがただちに対応できる容量の上限であるため、信頼性の目標ではなくしきい値ルールです。予算に割り当てるユーザーに見える成果はなく、ディスク容量の 0.5% を消費するという考え方にも意味がありません。

「リクエストレートがおかしいようだけど、設定できるしきい値がない」 — 固定の上限がないため、SLO もしきい値ルールも設定できません。季節的なベースラインを学習する異常検知ジョブに回し、スコアの信頼性が高まるまでには数週間分の履歴が必要だと伝えます。

「チェックアウトのインシデントが起きるたびに、なぜ 2 回もページャー通知が来るの?」 — GET kbn:/api/alerting/rules/_find でルールを一覧表示し、同じシグナルに対するバーンレートルールと生のしきい値ルールを探します。バーンレートルールはページャー通知用に残し、しきい値ルールはチケット用に変更したうえで、スローバーンウィンドウがページャー通知コネクターにルーティングされていないことを確認します。

ガイドライン

  • SLO を設計する前に計測手段を選択します。容量上限はしきい値ルールであり、上限のないシグナルは異常検知ジョブです。
  • インジケーターにフィールドを書き込む前に、すべてのフィールドを GET /<index>/_mapping または GET /_field_caps で確認します。慣例からフィールド名を推測してはいけません。
  • まず POST /_query を使って ES|QL で SLI を検証し、目標値は理想ではなく測定したベースラインに基づいて設定します。
  • objective.target は 0 から 1 までの小数です。99.5% の場合は 0.995 です。
  • タイムスライスのメトリックインジケーターには budgetingMethod: "timeslices" が必要です。
  • sli.kql.custom の good、total、filter フィールドは、API で定義されているとおり KQL です。クエリで使用するそれ以外のものはすべて ES|QL です。
  • SLO を更新すると、基盤となるトランスフォームがリセットされ、履歴が再計算されます。実行前にユーザーに警告してください。
  • クラスターには、transform と ingest の両方のロールを持つノードが必要です。
  • SLO が停止した場合やインデックスのマッピングを変更した後は、リセット操作を使用します。
  • グループ化する SLO は一意の値ごとにインスタンスを作成します。カーディナリティの高いフィールドを使った作成は拒否し、作成後に警告するのは避けてください。
  • Synthetics SLO はモニターとロケーションごとに自動でグループ化されます。groupBy は手動で設定しないでください。
  • バーンレートのアラートルールは SLO API では作成されません。高速バーンと低速バーンのウィンドウを異なる重大度に振り分けて、別途設定してください。
  • ルールを無効にするより、スヌーズするかメンテナンスウィンドウを開くことを優先します。
  • 削除を実行する前に確認してください。

運用

HTTP API(省略形)elastic CLI コマンド
POST /_queryelastic es esql query --format tsv --query '<esql>'
GET /_resolve/index/<pattern>elastic es indices resolve-index --name '<pattern>'
GET /<index>/_mappingelastic es indices get-mapping --index '<index>'
GET /_field_capselastic es field-caps --index '<index>' --fields '<fields>'
GET /_ml/anomaly_detectorselastic es ml get-jobs
GET kbn:/api/observability/sloselastic kb slo find-slos-op --space-id '<space>' --kql-query '<kql>'
POST kbn:/api/observability/sloselastic kb slo create-slo-op --space-id '<space>' --input-file <json>
GET kbn:/api/observability/slos/{id}elastic kb slo get-slo-op --space-id '<space>' --slo-id '<id>'
PUT kbn:/api/observability/slos/{id}elastic kb slo update-slo-op --space-id '<space>' --slo-id '<id>' --input-file <json>
DELETE kbn:/api/observability/slos/{id}elastic kb slo delete-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/_resetelastic kb slo reset-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/enableelastic kb slo enable-slo-op --space-id '<space>' --slo-id '<id>'
POST kbn:/api/observability/slos/{id}/disableelastic kb slo disable-slo-op --space-id '<space>' --slo-id '<id>'
GET kbn:/api/observability/slos/_definitionselastic kb slo get-definitions-op --space-id '<space>'
GET kbn:/api/alerting/rules/_findelastic kb alerting get-alerting-rules-find --filter '<kql>'
POST kbn:/api/alerting/rule/{id}elastic kb alerting post-alerting-rule-id --id '<id>' --input-file <json>
POST kbn:/api/alerting/rule/{id}/_snooze_scheduleelastic kb alerting post-alerting-rule-id-snooze-schedule --id '<id>' --input-file <json>
POST kbn:/api/alerting/rule/{id}/_disableelastic kb alerting post-alerting-rule-id-disable --id '<id>'
POST kbn:/api/maintenance_windowelastic kb maintenance-window post-maintenance-window --title '<title>' --input-file <json>
GET kbn:/api/synthetics/monitorsCLI の対応コマンドなし — 下記の CLI の不足点を参照
POST kbn:/api/synthetics/monitorsCLI の対応コマンドなし — 下記の CLI の不足点を参照
CLI の未対応部分。 elastic CLI 0.2.0 時点では、Synthetics モニター管理 API のバインディングはありません。stack kb 名前空間には Synthetics コマンドが用意されていません。上記の HTTP 簡略表記は引き続き正しい仕様であり、移植性も保たれているため、実行すべき内容を説明する際には引き続き使用してください。ただし、CLI の呼び出し方をでっち上げてはいけません。モニターの作成と編集には、Kibana の Synthetics アプリ、Synthetics プロジェクト、またはすでに認証情報を持つツールから Kibana API を直接呼び出す方法を使用してください。このスキルのその他すべての機能には、バーンレートルールやすべての SLO 操作も含め、動作する CLI バインディングがあります。

コメント