简介
Alertmanager,顾名思义,警告管理,配合 Prometheus,可以实现将服务器、应用中超出指标的信息通知出去。
本文介绍如何使用 Alertmanager 配置邮件通知。
其实还有对接 Alertmanager,将告警通知到办公软件的中间件(如钉钉、飞书),参考下面这篇文章。
准备
Prometheus 配置如下,添加了一个关于 MySQL 的规则文件,监测一个节点(本机)
其中,9104 是 MySQL 的采集服务,9100 是节点,即服务器的硬件指标(单纯监测 MySQL 的话,这个可省略)
更多参考下面这篇文章

MySQL 规则文件如下
yml
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,这里配置邮件通知的内容,配置文件如下:
yml
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,内容如下
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 }}
如下

这下是不是好看多了

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

完整配置如下
yml
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'
这回是不是更舒服了,是告警通知还是恢复通知,还有告警级别,从邮件标题上就看得到

邮件列表
