Alertmanager设置邮件通知

0 阅读3分钟

简介

Alertmanager,顾名思义,警告管理,配合 Prometheus,可以实现将服务器、应用中超出指标的信息通知出去。

本文介绍如何使用 Alertmanager 配置邮件通知。

其实还有对接 Alertmanager,将告警通知到办公软件的中间件(如钉钉、飞书),参考下面这篇文章。

准备

Prometheus 配置如下,添加了一个关于 MySQL 的规则文件,监测一个节点(本机)

其中,9104 是 MySQL 的采集服务,9100 是节点,即服务器的硬件指标(单纯监测 MySQL 的话,这个可省略)

更多参考下面这篇文章

在这里插入图片描述

MySQL 规则文件如下

groups:
  - name: MySQL监控告警规则
    rules:
      # 告警1:MySQL实例宕机
      - alert: MySQL实例宕机
        expr: mysql_up == 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "MySQL实例宕机(实例:{{ $labels.instance }})"
          description: "【描述】MySQL实例 {{ $labels.instance }} 已停止运行【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 登录服务器检查MySQL进程是否存在:ps -ef | grep mysql;(2) 查看MySQL日志:/var/log/mysql/ 或 datadir下的error.log;(3) 检查端口是否被占用:netstat -tulpn | grep 3306;(4) 尝试重启MySQL服务:systemctl restart mysqld。"

      # 告警2:MySQL连接数使用率超过80%
      - alert: MySQL连接数使用率过高
        expr: max_over_time(mysql_global_status_threads_connected[1m]) / mysql_global_variables_max_connections * 100 > 80
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "MySQL连接数使用率过高(实例:{{ $labels.instance }})"
          description: "【描述】{{ $labels.proj }} 的MySQL实例 {{ $labels.instance }} 连接数使用率超过80%【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 执行show processlist;查看慢查询/无用连接;(2) 优化业务代码,关闭未释放的连接;(3) 临时调高max_connections参数;(4) 检查是否存在连接泄露问题;(5) 考虑使用连接池优化连接复用。"

      # 告警3:MySQL运行线程占比超过60%
      - alert: MySQL运行线程占比过高
        expr: max_over_time(mysql_global_status_threads_running[1m]) / mysql_global_variables_max_connections * 100 > 60
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "MySQL运行线程占比过高(实例:{{ $labels.instance }})"
          description: "【描述】MySQL实例 {{ $labels.instance }} 运行线程数占最大连接数比例超过60%【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 执行show full processlist;分析耗时SQL;(2) 检查是否有大事务/锁等待;(3) 优化索引;(4) 调整innodb_thread_concurrency参数;(5) 排查服务器CPU/IO是否瓶颈。"

      # 告警4:MySQL从库IO线程未运行
      - alert: MySQL从库IO线程未运行
        expr: (mysql_slave_status_slave_io_running and ON (instance) mysql_slave_status_master_server_id > 0) == 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "MySQL从库IO线程未运行(实例:{{ $labels.instance }})"
          description: "【描述】MySQL从库 {{ $labels.instance }} 的IO线程停止运行【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 登录从库执行show slave status\\G查看Last_IO_Error;(2) 检查主从库网络连通性;(3) 验证主库账号权限;(4) 检查主库binlog是否存在;(5) 尝试重启IO线程:start slave io_thread;。"

      # 告警5:MySQL从库SQL线程未运行
      - alert: MySQL从库SQL线程未运行
        expr: (mysql_slave_status_slave_sql_running and ON (instance) mysql_slave_status_master_server_id > 0) == 0
        for: 0m
        labels:
          severity: critical
        annotations:
          summary: "MySQL从库SQL线程未运行(实例:{{ $labels.instance }})"
          description: "【描述】MySQL从库 {{ $labels.instance }} 的SQL线程停止运行【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 执行show slave status\\G查看Last_SQL_Error;(2) 检查主从库数据不一致/表结构差异;(3) 处理事务冲突;(4) 确认从库磁盘空间是否充足;(5) 检查SQL_MODE是否与主库一致。"

      # 告警6:MySQL主从复制延迟超过阈值
      - alert: MySQL主从复制延迟过高
        expr: ((mysql_slave_status_seconds_behind_master - mysql_slave_status_sql_delay) and ON (instance) mysql_slave_status_master_server_id > 0) > 30
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "MySQL主从复制延迟过高(实例:{{ $labels.instance }})"
          description: "【描述】MySQL从库 {{ $labels.instance }} 复制延迟超过30秒【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 查看从库IO/SQL线程是否正常;(2) 检查主库是否有大事务/慢查询;(3) 优化从库配置;(4) 确认从库硬件性能;(5) 若延迟持续,考虑临时停止大业务写入。"

      # 告警7:MySQL新增慢查询
      - alert: MySQL新增慢查询
        expr: increase(mysql_global_status_slow_queries[1m]) > 0
        for: 2m
        labels:
          severity: warning
        annotations:
          summary: "MySQL新增慢查询(实例:{{ $labels.instance }})"
          description: "【描述】MySQL实例 {{ $labels.instance }} 近1分钟内出现新的慢查询【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 查看慢查询日志定位慢SQL;(2) 使用explain分析SQL执行计划;(3) 优化索引;(4) 调整SQL语句;(5) 临时调高long_query_time参数。"

      # 告警8:MySQL InnoDB日志写入等待
      - alert: MySQL InnoDB日志写入等待
        expr: rate(mysql_global_status_innodb_log_waits[15m]) > 10
        for: 0m
        labels:
          severity: warning
        annotations:
          summary: "MySQL InnoDB日志写入等待(实例:{{ $labels.instance }})"
          description: "【描述】MySQL实例 {{ $labels.instance }} InnoDB日志写入等待频率过高【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 检查磁盘IO性能;(2) 优化innodb_log_file_size;(3) 调整innodb_flush_log_at_trx_commit;(4) 检查是否有大量小事务;(5) 升级磁盘。"

      # 告警9:MySQL实例1分钟内重启
      - alert: MySQL实例近期重启
        expr: mysql_global_status_uptime < 60
        for: 0m
        labels:
          severity: info
        annotations:
          summary: "MySQL实例近期重启(实例:{{ $labels.instance }})"
          description: "【描述】MySQL实例 {{ $labels.instance }} 在1分钟内发生重启【标签】{{ $labels }}【数值】{{ printf \"%.4f\" $value }}"
          suggestion: "(1) 查看MySQL错误日志,确认重启原因;(2) 检查服务器是否发生OOM;(3) 确认是否有运维操作触发重启;(4) 检查系统资源是否异常;(5) 若为异常崩溃,升级MySQL版本。"

配置完,浏览器访问 Prometheus、Alertmanager 的地址,能访问到以下界面,说明配置没问题

(Prometheus 后台)

在这里插入图片描述

(Alertmanager 后台)

在这里插入图片描述

配置

接着配置 Alertmanager,这里配置邮件通知的内容,配置文件如下:

global:
  #qq服务器
  smtp_smarthost: 'smtp.qq.com:587'
  #发邮件的邮箱
  smtp_from: '1076558989@qq.com'
  #发邮件的邮箱用户名,也就是你的邮箱
  smtp_auth_username: '1076558989@qq.com'
  #发邮件的邮箱授权码,非QQ登录密码
  smtp_auth_password: 'wceXXXXXXXXXXaji'
  #进行tls验证
  smtp_require_tls: true

route:
  group_by: ['alertname']
  # 当收到告警的时候,等待group_wait配置的时间,看是否还有告警,如果有就一起发出去
  group_wait: 10s
  #  如果上次告警信息发送成功,此时又来了一个新的告警数据,则需要等待group_interval配置的时间才可以发送出去
  group_interval: 10s
  # 如果上次告警信息发送成功,且问题没有解决,则等待 repeat_interval配置的时间再次发送告警数据
  repeat_interval: 10s
  # 全局报警组,选择哪个接收者
  receiver: email

receivers:
  - name: 'email'
    #收邮件的邮箱
    email_configs:
    - to: '1076558989@qq.com'

我这里用的是 QQ 邮箱的,授权码获取或者网易邮箱的,参考下面这篇博客

配置完之后,测试一下,停止本机 MySQL 服务,看是否有告警,以及告警是否发邮件

在这里插入图片描述

告警有了,MySQL 实例宕机规则被触发

在这里插入图片描述

邮件也通知了

在这里插入图片描述

优化

显然,前面邮件的模板不好看,不直观、不够友好。邮件模板可以通过下面的操作进行设置

在这里插入图片描述

在当前目录下创建一个邮件模板,email.html,内容如下

{{ define "email.html" }}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>监控告警通知</title>
    <style>
        body { font-family: "Microsoft YaHei", Arial, sans-serif; font-size: 14px; line-height: 1.8; color: #333; margin: 20px; text-align: left; }
        .alert-box { padding: 20px; border-radius: 6px; max-width: 600px; margin: 0 0 20px 0; text-align: left; }
        .firing { background-color: #fff5f5; border: 1px solid #ffccc7; }
        .resolved { background-color: #f0f9eb; border: 1px solid #b7eb8f; }
        .title { font-size: 16px; font-weight: bold; margin-bottom: 15px; }
        .item { margin: 8px 0; }
        .label { display: inline-block; width: 80px; font-weight: bold; color: #666; }
        .level-info { margin-top:20px; padding:15px; background:#f8f9fa; border-radius:6px; max-width:600px; text-align: left; }
        .level-title { font-weight:bold; margin-bottom:8px; color:#333; }
        .level-item { margin:4px 0; }
    </style>
</head>
<body>
    {{ range $i, $alert := .Alerts }}
    <div class="alert-box {{ $alert.Status }}">
        <div class="title">
            {{ if eq $alert.Status "firing" }}🔴 监控告警触发{{ else }}🟢 监控告警恢复{{ end }}
        </div>
        <div class="item"><span class="label">级别:</span>{{ index $alert.Labels "severity" }}</div>
        <div class="item"><span class="label">实例:</span>{{ index $alert.Labels "instance" }}</div>
        <div class="item"><span class="label">时间:</span>{{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}</div>
        {{ with $alert.Annotations }}
        <div class="item"><span class="label">概要:</span>{{ .summary }}</div>
        <div class="item"><span class="label">详情:</span>{{ .description }}</div>
        {{ if .suggestion }}
        <div class="item"><span class="label">建议:</span>{{ .suggestion }}</div>
        {{ end }}
        {{ end }}
    </div>
    {{ end }}

    <div class="level-info">
        <div class="level-title">📌 告警级别说明</div>
        <div class="level-item">• critical:<b>紧急</b>,服务中断/严重故障,需立即处理</div>
        <div class="level-item">• warning:<b>警告</b>,指标异常,需关注处理</div>
        <div class="level-item">• info:<b>提示</b>,资源闲置/配置变更,无需紧急处理</div>
    </div>
</body>
</html>
{{ end }}

如下

在这里插入图片描述

这下是不是好看多了

在这里插入图片描述

其他

除此之外,还有其他配置,如邮件标题、抄送人、告警恢复是否通知

在这里插入图片描述

完整配置如下

global:
  # qq服务器
  smtp_smarthost: 'smtp.qq.com:587'
  # 发邮件的邮箱
  smtp_from: '1076558989@qq.com'
  # 发邮件的邮箱用户名,也就是你的邮箱
  smtp_auth_username: '1076558989@qq.com'
  # 发邮件的邮箱授权码,非QQ登录密码
  smtp_auth_password: 'wcXXXXXXXXXXaji'
  # 进行tls验证
  smtp_require_tls: true

route:
  group_by: ['alertname']
  # 当收到告警的时候,等待group_wait配置的时间,看是否还有告警,如果有就一起发出去
  group_wait: 10s
  # 如果上次告警信息发送成功,此时又来了一个新的告警数据,则需要等待group_interval配置的时间才可以发送出去
  group_interval: 30s
  # 如果上次告警信息发送成功,且问题没有解决,则等待 repeat_interval配置的时间再次发送告警数据
  repeat_interval: 30s
  # 全局报警组,这个参数是必选的
  receiver: email

receivers:
  - name: 'email'
    # 收邮件的邮箱
    email_configs:
    # 通知人,多个用,分割
    - to: '1076558989@qq.com'
      # 警告解除是否通知
      send_resolved: true
      # 邮件模板
      html: '{{ template "email.html" . }}'
      # 邮件格式
      headers:
        # 标题
        Subject: '{{ if eq .Status "firing" }}【告警通知】{{ else }}【恢复通知】{{ end }}监控告警通知 ({{ if eq .CommonLabels.severity "critical" }}紧急{{ else if eq .CommonLabels.severity "warning" }}警告{{ else }}提示{{ end }})'
        # 抄送人
        CC: '1076558989@qq.com'

templates:
- 'templates/*.html'

这回是不是更舒服了,是告警通知还是恢复通知,还有告警级别,从邮件标题上就看得到

在这里插入图片描述

邮件列表

在这里插入图片描述