Prometheus告警管理

2022/05/05 Prometheus

Prometheus告警管理

Prometheus 包含一个 报警模块 ,就是我们的 AlertManager,Alertmanager 主要用于接收 Prometheus 发送的告警信息,它支持丰富的告警通知渠道,而且很容易做到告警信息进行去重,降噪,分组等,是一款前卫的告警通知系统。

  • 如何构建良好的警报机制
  • 如何安装和配置Alertmanager
  • 如何使用它来路由通知和管理维护

警报

警报可以为我们提供一些指示,表明我们环境中的某些状态已发生变化,且通常会是比想象更糟的情况。一个好警报的关键是能够在正确的时间、以正确的理由和正确的速度发送,并在其中放入有用的信息。

警报方法中最常见的反模式是发送过多的警报。对于监控来说,过多的警报相当于“狼来了”这样的故事。收件人会对警告变得麻木,然后将其拒之门外,而重要的警报常常被淹没在无关紧要的更新中。

通常发送过多警报的原因可能包括:

  • 警报缺少可操作性,它只是提供信息。你应关闭所有这些警报,或将其转换为计算速率的计数器,而不是发出警报。
  • 故障的主机或服务上游会触发其下游的所有内容的警报。你应确保警报系统识别并抑制这些重复的相邻警报。
  • 对原因而不是症状(symptom)进行警报。症状是应用程序停止工作的迹象,它们可能是由许多原因导致的各种问题的表现。API或网站的高延迟是一种症状,这种症状可能由许多问题导致:高数据库使用率、内存问题、磁盘性能等。对症状发送警报可以识别真正的问题。仅对原因(例如高数据库使用率)发出警报也可能识别出问题(但通常很可能不会)。对于这个应用程序,高数据库使用率可能是完全正常的,并且可能不会对最终用户或应用程序造成性能问题。作为一个内部状态,发送警报是没有意义的。这种警报可能会导致工程师错过更重要的问题,因为他们已经对大量不可操作且基于原因的警报变得麻木。你应该关注基于症状的警报,并依赖你的指标或其他诊断数据来确定原因。

第二种最常见的反模式是警报的错误分类。有时,这也意味着重要的警报会隐藏在其他警报中。但有时候,警报会被发送到错误的地方或者带有不正确的紧急情况说明。

第三种反模式是发送无用的警报,尤其当收件人通常是一个疲惫的、刚刚被叫醒的工程师(并且这可能是他在夜班中收到的第三个或第四个通知)时。

良好的警报应该具备以下几个关键特征:

  • 适当数量的警报,关注症状而不是原因。噪声警报会导致警报疲劳,最终警报会被忽略。修复警报不足比修复过度警报更容易。
  • 应设置正确的警报优先级。如果警报是紧急的,那么它应该快速路由到负责响应的一方。如果警报不紧急,那么我们应该以适当的速度发送警报,以便在需要时做出响应。
  • 警报应包括适当的上下文,以便它们立即可以使用。

Alertmanager如何工作

Alertmanager处理从客户端发来的警报,客户端通常是Prometheus服务器。Alertmanager对警报进行去重、分组,然后路由到不同的接收器,如电子邮件、短信或SaaS服务。你还可以使用Alertmanager管理维护。

我们将在Prometheus服务器上编写警报规则,这些规则将使用我们收集的指标并在指定的阈值或标准上触发警报。我们还将看到如何为警报添加一些上下文。当指标达到阈值或标准时,会生成一个警报并将其推送到Alertmanager。警报在Alertmanager上的HTTP端点上接收。一个或多个Prometheus服务器可以将警报定向到单个Alertmanager,或者你可以创建一个高可用的Alertmanager集群。

收到警报后,Alertmanager会处理警报并根据其标签进行路由。一旦路径确定,它们将由Alertmanager发送到外部目的地,如电子邮件、短信或聊天工具。

AlertManager 架构

Alertmanager 由以下 6 部分组成:

  • API 组件 用于接收 Prometheus Server 的 http 请求,主要是告警相关的内容。
  • Alert Provider 组件 API 层将来自 Prometheus Server 的告警信息存储到 Alert Provider 上。
  • Dispatcher 组件 不断的通过订阅的方式从 Alert Provider 获取新的告警,并根据 yaml 配置的 routing tree 将告警通过 label 路由到不同的分组中,以实现告警信息的分组处理。
  • Notification Pipeline 组件 这是一个责任链模式的组件,它通过一系列的逻辑(抑制、静默、去重)来优化告警质量。
  • Silence Provider 组件 API 层将来自 prometheus server 的告警信息存储到 silence provider 上,然后由这个组件实现去重逻辑处理。
  • Notify Provider 组件 是 Silence Provider 组件的下游,会在本地记录日志,并通过 peers 的方式将日志广播给集群中的其他节点,判断当前节点自身或者集群中其他节点是否已经发送过了,避免告警信息在集群中重复出现。

AlertManager 部署

下载

wget https://github.com/prometheus/alertmanager/releases/download/v0.24.0/alertmanager-0.24.0.linux-amd64.tar.gz  
tar -xf alertmanager-0.24.0.linux-amd64.tar.gz  

配置

global:  
  resolve_timeout: 5m  
  
route:  
  group_by: ['alertname']  
  group_wait: 30s  
  group_interval: 5m  
  repeat_interval: 1h  
  receiver: 'web.hook'  
receivers:  
  - name: 'web.hook'  
    webhook_configs:  
      - url: 'http://127.0.0.1:5001/'  
inhibit_rules:  
  - source_match:  
      severity: 'critical'  
    target_match:  
      severity: 'warning'  
    equal: ['alertname', 'dev', 'instance']  

Alertmanager配置中一般会包含以下几个主要部分:

  • 全局配置(global):用于定义一些全局的公共参数,如全局的SMTP配置,Slack配置等内容。
  • 模板(templates):用于定义告警通知时的模板,如HTML模板,邮件模板等。
  • 告警路由(route):根据标签匹配,确定当前告警应该如何处理。
  • 接收人(receivers):接收人是一个抽象的概念,它可以是一个邮箱也可以是 微信 , Slack 或者 Webhook 等,接收人一般配合告警路由使用。
  • 抑制规则(inhibit_rules):合理设置抑制规则可以减少垃圾告警的产生。

具体字段解释:

  • global 这个是全局设置
  • resolve_timeout 当告警的状态有firing变为resolve的以后还要呆多长时间,才宣布告警解除。这个主要是解决某些监控指标在阀值边缘上波动,一会儿好一会儿不好。
  • route 是个重点,告警内容从这里进入,寻找自己应该用那种策略发送出去。
  • receiver 一级的receiver,也就是默认的receiver,当告警进来后没有找到任何子节点和自己匹配,就用这个receiver。
  • group_by 告警应该根据那些标签进行分组。
  • group_wait 同一组的告警发出前要等待多少秒,这个是为了把更多的告警一个批次发出去。
  • group_interval 同一组的多批次告警间隔多少秒后,才能发出。
  • repeat_interval 重复的告警要等待多久后才能再次发出去。
  • routes 也就是子节点了,配置项和上面一样。告警会一层层的找,如果匹配到一层,并且这层的continue选项为true,那么他会再往下找,如果下层节点不能匹配那么他就用区配的这一层的配置发送告警。如果匹配到一层,并且这层的continue选项为false,那么他会直接用这一层的配置发送告警,就不往下找了。
  • match_re 用于匹配label。此处列出的所有label都匹配到才算匹配。
  • inhibit_rules这个叫做抑制项,通过匹配源告警来抑制目的告警。比如说当我们的主机挂了,可能引起主机上的服务,数据库,中间件等一些告警,假如说后续的这些告警相对来说没有意义,我们可以用抑制项这个功能,让Prometheus只发出主机挂了的告警。
  • source_match 根据label匹配源告警。
  • target_match 根据label匹配目的告警。
  • equal 此处的集合的label,在源和目的里的值必须相等。如果该集合的内的值再源和目的里都没有,那么目的告警也会被抑制。

启动服务

# 查看帮助  
./alertmanager -h  
# 可以直接启动,但是不提倡,最好配置alertmanager.service  
./alertmanager  

配置alertmanager.service启动脚本

# 默认端口9093  
cat >/usr/lib/systemd/system/alertmanager.service<<EOF  
[Unit]  
Description=alertmanager  
  
[Service]  
WorkingDirectory=/opt/prometheus/alertmanager/alertmanager-0.24.0.linux-amd64  
ExecStart=/opt/prometheus/alertmanager/alertmanager-0.24.0.linux-amd64/alertmanager --config.file=/opt/prometheus/alertmanager/alertmanager-0.24.0.linux-amd64/alertmanager.yml --storage.path=/opt/prometheus/alertmanager/alertmanager-0.24.0.linux-amd64/data --web.listen-address=:9093 --data.retention=120h  
Restart=on-failure  
  
[Install]  
WantedBy=multi-user.target  
EOF  

启动服务

# 执行 systemctl daemon-reload 命令重新加载systemd  
systemctl daemon-reload  
# 启动  
systemctl start alertmanager  
# 检查  
systemctl status alertmanager  
netstat -tnlp|grep :9093  
ps -ef|grep alertmanager  

web访问:http://ip:9093

在Prometheus中设置告警规则

在Prometheus 配置中添加报警规则配置,配置文件中 rule_files 就是用来指定报警规则文件的,如下配置即指定存放报警规则的目录为/etc/prometheus,规则文件为rules.yml:

rule_files:  
- /etc/prometheus/rules.yml  

设置报警规则: 警报规则允许基于 Prometheus 表达式语言的表达式来定义报警报条件的,并在触发警报时发送通知给外部的接收者(Alertmanager),一条警报规则主要由以下几部分组成:

  • alert——告警规则的名称。
  • expr——是用于进行报警规则 PromQL 查询语句。
  • for——评估告警的等待时间(Pending Duration)。
  • labels——自定义标签,允许用户指定额外的标签列表,把它们附加在告警上。
  • annotations——用于存储一些额外的信息,用于报警信息的展示之类的。

rules.yml如下所示:

groups:  
- name: example  
  rules:  
  - alert: high_memory  
    # 当内存占有率超过10%,持续1min,则触发告警  
    expr: 100 - ((node_memory_MemAvailable_bytes{instance="192.168.182.110:9100",job="node_exporter"} * 100) / node_memory_MemTotal_bytes{instance="192.168.182.110:9100",job="node_exporter"}) > 90  
    for: 1m  
    labels:  
      severity: page  
    annotations:  
      summary: spike memeory  

AlertManager 告警通道配置

## Alertmanager 配置文件  
global:  
  resolve_timeout: 5m  
  # smtp配置  
  smtp_from: "xxx@qq.com"  
  smtp_smarthost: 'smtp.qq.com:465'  
  smtp_auth_username: "xxx@qq.com"  
  smtp_auth_password: "auth_pass"  
  smtp_require_tls: true  
  
# email、企业微信的模板配置存放位置,钉钉的模板会单独讲如果配置。  
templates:  
  - '/data/alertmanager/templates/*.tmpl'  
# 路由分组  
route:  
  receiver: ops  
  group_wait: 30s # 在组内等待所配置的时间,如果同组内,30秒内出现相同报警,在一个组内出现。  
  group_interval: 5m # 如果组内内容不变化,合并为一条警报信息,5m后发送。  
  repeat_interval: 24h # 发送报警间隔,如果指定时间内没有修复,则重新发送报警。  
  group_by: [alertname]  # 报警分组  
  routes:  
      - match:  
          team: operations  
        group_by: [env,dc]  
        receiver: 'ops'  
      - match_re:  
          service: nginx|apache  
        receiver: 'web'  
      - match_re:  
          service: hbase|spark  
        receiver: 'hadoop'  
      - match_re:  
          service: mysql|mongodb  
        receiver: 'db'  
# 接收器  
# 抑制测试配置  
      - receiver: ops  
        group_wait: 10s  
        match:  
          status: 'High'  
# ops  
      - receiver: ops # 路由和标签,根据match来指定发送目标,如果 rule的lable 包含 alertname, 使用 ops 来发送  
        group_wait: 10s  
        match:  
          team: operations  
# web  
      - receiver: db # 路由和标签,根据match来指定发送目标,如果 rule的lable 包含 alertname, 使用 db 来发送  
        group_wait: 10s  
        match:  
          team: db  
# 接收器指定发送人以及发送渠道  
receivers:  
# ops分组的定义  
- name: ops  
  email_configs:  
  - to: '9935226@qq.com,10000@qq.com'  
    send_resolved: true  
    headers:  
      subject: "[operations] 报警邮件"  
      from: "警报中心"  
      to: "小煜狼皇"  
  # 钉钉配置  
  webhook_configs:  
  - url: http://localhost:8070/dingtalk/ops/send  
    # 企业微信配置  
  wechat_configs:  
  - corp_id: 'ww5421dksajhdasjkhj'  
    api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'  
    send_resolved: true  
    to_party: '2'  
    agent_id: '1000002'  
    api_secret: 'Tm1kkEE3RGqVhv5hO-khdakjsdkjsahjkdksahjkdsahkj'  
  
# web  
- name: web  
  email_configs:  
  - to: '9935226@qq.com'  
    send_resolved: true  
    headers: { Subject: "[web] 报警邮件"} # 接收邮件的标题  
  webhook_configs:  
  - url: http://localhost:8070/dingtalk/web/send  
  - url: http://localhost:8070/dingtalk/ops/send  
# db  
- name: db  
  email_configs:  
  - to: '9935226@qq.com'  
    send_resolved: true  
    headers: { Subject: "[db] 报警邮件"} # 接收邮件的标题  
  webhook_configs:  
  - url: http://localhost:8070/dingtalk/db/send  
  - url: http://localhost:8070/dingtalk/ops/send  
# hadoop  
- name: hadoop  
  email_configs:  
  - to: '9935226@qq.com'  
    send_resolved: true  
    headers: { Subject: "[hadoop] 报警邮件"} # 接收邮件的标题  
  webhook_configs:  
  - url: http://localhost:8070/dingtalk/hadoop/send  
  - url: http://localhost:8070/dingtalk/ops/send  
  
# 抑制器配置  
inhibit_rules: # 抑制规则  
  - source_match: # 源标签警报触发时抑制含有目标标签的警报,在当前警报匹配 status: 'High'  
      status: 'High'  # 此处的抑制匹配一定在最上面的route中配置不然,会提示找不key。  
    target_match:  
      status: 'Warning' # 目标标签值正则匹配,可以是正则表达式如: ".*MySQL.*"  
    equal: ['alertname','operations', 'instance'] # 确保这个配置下的标签内容相同才会抑制,也就是说警报中必须有这三个标签值才会被抑制。 

一般企业钉钉、邮件、webhook告警通道比较常用,尤其是webhook,一般都会通过webhook对接公司内部的统一告警平台。


数据模型

prometheus将所有数据存储为时间序列:属于相同 metric名称和相同标签组(键值对)的时间戳值流。

metric 和 标签: 每一个时间序列都是由其 metric名称和一组标签(键值对)组成唯一标识。

metric名称代表了被监控系统的一般特征(如 http_requests_total代表接收到的HTTP请求总数)。它可能包含ASCII字母和数字,以及下划线和冒号,它必须匹配正则表达式[a-zA-Z_:][a-zA-Z0-9_:]*。

注意:冒号是为用户定义的记录规则保留的,不应该被exporter使用。

标签给prometheus建立了多维度数据模型:对于相同的 metric名称,标签的任何组合都可以标识该 metric的特定维度实例(例如:所有使用POST方法到 /api/tracks 接口的HTTP请求)。查询语言会基于这些维度进行过滤和聚合。更改任何标签值,包括添加或删除标签,都会创建一个新的时间序列。

标签名称可能包含ASCII字母、数字和下划线,它必须匹配正则表达式[a-zA-Z_][a-zA-Z0-9_]*。另外,以双下划线__开头的标签名称仅供内部使用。

标签值可以包含任何Unicode字符。标签值为空的标签被认为是不存在的标签。

表示法: 给定 metric名称和一组标签,通常使用以下表示法标识时间序列:

{

Search

    微信好友

    博士的沙漏

    Table of Contents