实用异常检测

2015年6月18日作者 Brian Brazil

在他的致监控/指标/告警公司的公开信中,John Allspaw 断言,试图“在正确的时间完美地检测异常是不可能的”。

我见过一些有才华的工程师尝试构建系统,以根据时间序列数据自动检测和诊断问题。虽然让演示正常工作当然是可能的,但数据总是充满了太多噪音,导致这种方法除了用于最简单的真实世界系统外,都无法奏效。

但希望并未完全破灭。有许多常见的异常情况,您可以通过自定义规则来检测和处理。Prometheus 查询语言为您提供了发现这些异常同时避免误报的工具。

构建查询

服务中一个常见的问题是,少数服务器的性能不如其他服务器,例如响应延迟增加。

假设我们有一个指标 instance:latency_seconds:mean5m,它表示服务每个实例的平均查询延迟,该指标通过记录规则从一个 Summary 类型的指标计算得出。

一个简单的入手方法是查找延迟比平均值高出两个标准差以上的实例。

  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个查询。你为所有这些条件创建了一个告警定义。

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 发送到您的聊天、工单或寻呼系统。一段时间后,您可能会发现,引发告警的通常原因并没有一个彻底的修复方案,但可以通过自动化操作(如重启、重引导或更换机器)来解决问题。

与其让人类来处理这种重复性任务,一个选择是让 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 支持则可以触发自动修复。这一切结合起来,使待命工程师能够专注于他们能产生最大影响的问题上。

在为您的服务定义告警时,另请参阅我们的告警最佳实践