実践的な異常検知

2015年6月18日筆者: Brian Brazil

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

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

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

クエリの構築

サービス内でよくある問題は、少数のサーバーが他のサーバーほどパフォーマンスを発揮しておらず、応答遅延が増加している場合などです。

サービスインスタンスごとの平均クエリレイテンシを表すメトリクス `instance:latency_seconds:mean5m` があるとします。これは、記録ルールによって、Summary メトリクスから計算されたものです。

開始するための簡単な方法は、平均値よりも標準偏差の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 クエリ言語は、監視データの豊富な処理を可能にします。これにより、信号対ノイズ比の良いアラートを作成でき、Alertmanager の汎用 Webhook サポートは自動修復をトリガーできます。これらすべてを組み合わせることで、オンコールエンジニアは最も影響を与えることができる問題に集中できます。

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