実践的な異常検知

John Allspaw氏は、彼の監視/メトリクス/アラート企業への公開書簡の中で、「異常を完璧に、適切なタイミングで検知することは不可能である」と断言しています。

私は、優秀なエンジニアが時系列データに基づいて問題を自動的に検知・診断するシステムを構築しようとする試みをいくつか見てきました。確かにデモを動作させることは可能ですが、データは常にノイズが多すぎて、このアプローチは現実世界の最も単純なシステム以外では機能しないことが判明しました。

しかし、希望はすべて失われたわけではありません。カスタムビルドルールで検知および処理できる一般的な異常はたくさんあります。Prometheusのクエリ言語は、誤検知を避けながらこれらの異常を発見するためのツールを提供します。

クエリの構築

サービス内でよくある問題は、少数のサーバーが他のサーバーと比べてパフォーマンスが低い場合です。例えば、応答レイテンシの増加などが挙げられます。

instance:latency_seconds:mean5mというメトリックがあるとしましょう。これは、サービスの各インスタンスの平均クエリレイテンシを表し、記録ルールを介してサマリーメトリックから計算されます。

簡単な開始方法は、平均より2標準偏差以上高いレイテンシを持つインスタンスを探すことです。

  instance:latency_seconds:mean5m
> on (job) group_left()
  (
      avg by (job)(instance:latency_seconds:mean5m)
    + on (job)
      2 * stddev by (job)(instance:latency_seconds:mean5m)
  )

これを試してみると、レイテンシが非常に密集している場合に誤検知が発生することがわかります。そのため、インスタンスのレイテンシが平均の20%以上である必要があるという要件を追加します。

  (
      instance:latency_seconds:mean5m
    > on (job) group_left()
      (
          avg by (job)(instance:latency_seconds:mean5m)
        + on (job)
          2 * stddev by (job)(instance:latency_seconds:mean5m)
      )
  )
> on (job) group_left()
  1.2 * avg by (job)(instance:latency_seconds:mean5m)

最終的に、誤検知はトラフィックが少ないレベルで発生する傾向があることがわかります。各インスタンスに1秒あたり1クエリ分のトラフィックがあるという要件を追加します。このすべてのアラート定義を作成します。

groups:
- name: Practical Anomaly Detection
  rules:
  - alert: InstanceLatencyOutlier
    expr: >
      (
            (
                instance:latency_seconds:mean5m
              > on (job) group_left()
                (
                    avg by (job)(instance:latency_seconds:mean5m)
                  + on (job)
                    2 * stddev by (job)(instance:latency_seconds:mean5m)
                )
            )
          > on (job) group_left()
            1.2 * avg by (job)(instance:latency_seconds:mean5m)
        and on (job)
            avg by (job)(instance:latency_seconds_count:rate5m)
          >
            1
      )
    for: 30m

自動アクション

上記のアラートはAlertmanagerに送信され、そこからチャット、チケット、またはページングシステムに送信されます。しばらくすると、アラートの通常の原因は適切な修正がないものですが、再起動、リブート、またはマシンの交換などの自動アクションで問題が解決することがわかる場合があります。

人間がこの反復的なタスクを処理するのではなく、AlertmanagerがアラートをWebサービスに送信し、適切なスロットリングと安全機能を備えてアクションを実行するという選択肢があります。

汎用Webhookは、選択したHTTPエンドポイントにアラート通知を送信します。これを使用する簡単なAlertmanager設定は次のようになります。

# A simple notification configuration which only sends alert notifications to
# an external webhook.
receivers:
- name: restart_webhook
  webhook_configs:
    url: "http://example.org/my/hook"

route:
  receiver: restart_webhook

まとめ

Prometheusクエリ言語は、監視データのリッチな処理を可能にします。これにより、S/N比の高いアラートを作成でき、Alertmanagerの汎用Webhookサポートは自動修復をトリガーできます。これらがすべて組み合わさることで、オンコールエンジニアは最も影響を与えることができる問題に集中できます。

サービスのアラートを定義する際には、アラートのベストプラクティスも参照してください。