外观
MySQL 告警策略与故障分级
告警策略概述
告警的重要性
MySQL 告警是数据库运维的重要组成部分,能够帮助运维人员及时发现和解决问题,避免或减少业务损失。有效的告警策略可以:
- 提前发现潜在问题
- 减少故障定位时间
- 确保数据库服务可用性
- 降低运维成本
- 提高系统可靠性
告警设计原则
| 原则 | 描述 |
|---|---|
| 及时性 | 告警必须及时,以便快速响应 |
| 准确性 | 减少误报和漏报 |
| 分级告警 | 根据问题影响程度分级 |
| 可操作 | 告警信息必须包含可操作的信息 |
| 告警抑制 | 避免重复告警和告警风暴 |
| 告警升级 | 长时间未处理的告警自动升级 |
| 多渠道通知 | 确保告警能够送达相关人员 |
故障分级
分级标准
根据故障的影响范围、严重程度和恢复时间要求,MySQL 故障通常分为以下几个级别:
| 级别 | 名称 | 描述 | 示例 | 恢复时间要求 |
|---|---|---|---|---|
| P1 | 紧急 | 数据库完全不可用,业务完全中断 | - MySQL 服务停止 - 主从复制完全中断 - 数据丢失 | 立即响应(< 5 分钟) |
| P2 | 高优先级 | 数据库性能严重下降,部分业务受影响 | - 连接数接近上限 - 慢查询突增 - 主从延迟大 | 15 分钟内响应 |
| P3 | 中优先级 | 数据库存在隐患,可能影响性能 | - 磁盘空间不足 - 缓存命中率下降 - 锁等待增加 | 1 小时内响应 |
| P4 | 低优先级 | 数据库存在可优化项 | - 索引使用率低 - 配置不合理 - 慢查询少量增加 | 24 小时内响应 |
分级管理
响应流程
| 级别 | 响应流程 |
|---|---|
| P1 | 1. 立即通知所有 DBA 成员 2. 10 分钟内开始处理 3. 每 15 分钟更新一次状态 4. 2 小时内提供初步分析 5. 恢复后进行详细复盘 |
| P2 | 1. 通知值班 DBA 2. 30 分钟内开始处理 3. 每 30 分钟更新一次状态 4. 4 小时内提供分析报告 |
| P3 | 1. 通知相关 DBA 2. 1 小时内开始处理 3. 24 小时内解决 |
| P4 | 1. 记录问题 2. 安排在维护窗口解决 |
通知方式
| 级别 | 通知方式 | 通知频率 |
|---|---|---|
| P1 | - 短信 - 电话 - 即时通讯工具 - 邮件 | 立即发送,未确认则 5 分钟后重发 |
| P2 | - 短信 - 即时通讯工具 - 邮件 | 立即发送,未确认则 15 分钟后重发 |
| P3 | - 即时通讯工具 - 邮件 | 立即发送 |
| P4 | - 邮件 | 每日汇总发送 |
告警指标与阈值
可用性告警
版本差异
| 指标 | MySQL 5.6 | MySQL 5.7 | MySQL 8.0 |
|---|---|---|---|
| MGR 集群状态 | ❌ | ✅ | ✅ |
| GTID 复制状态 | ⚠️ 实验性 | ✅ | ✅ |
| 事务锁监控 | 基础 | 增强 | 全面 |
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| MySQL 服务状态 | MySQL 进程是否运行 | systemctl status mysqld 或 SHOW GLOBAL STATUS LIKE 'Uptime'; | 服务停止 | P1 |
| 主从复制状态 | 复制 IO/SQL 线程状态 | SHOW SLAVE STATUS\G | Slave_IO_Running 或 Slave_SQL_Running 为 No | P1 |
| MGR 集群状态 | MGR 成员状态 | SELECT * FROM performance_schema.replication_group_members; | 有成员状态非 ONLINE | P1 |
连接告警
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| 当前连接数 | 当前活跃的连接数 | SHOW GLOBAL STATUS LIKE 'Threads_connected'; | 超过 max_connections 的 80% | P2 |
| 连接错误数 | 连接失败的次数 | SHOW GLOBAL STATUS LIKE 'Connection_errors_%'; | 每分钟 > 5 次 | P3 |
| 拒绝连接数 | 因连接数满而拒绝的连接 | SHOW GLOBAL STATUS LIKE 'Threads_rejected'; | 任何非零值 | P2 |
性能告警
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| 慢查询数 | 慢查询的数量 | SHOW GLOBAL STATUS LIKE 'Slow_queries'; | 每分钟 > 10 次 | P2 |
| 活跃线程数 | 正在执行查询的线程数 | SHOW GLOBAL STATUS LIKE 'Threads_running'; | 超过 CPU 核心数 * 2 | P2 |
| 锁等待时间 | 锁等待的总时间 | SHOW GLOBAL STATUS LIKE 'Innodb_row_lock_time'; | 每分钟 > 1000ms | P3 |
| 死锁次数 | 发生死锁的次数 | SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks'; | 任何非零值 | P3 |
资源告警
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| 磁盘空间使用率 | 数据目录磁盘使用率 | df -h | > 80% | P3 |
| 内存使用率 | MySQL 内存使用情况 | SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_%'; | 缓冲池命中率 < 95% | P3 |
| CPU 使用率 | MySQL 进程 CPU 使用率 | top -p $(pidof mysqld) | 持续 > 80% | P2 |
| 临时表使用率 | 磁盘临时表占比 | SHOW GLOBAL STATUS LIKE 'Created_tmp%tables'; | Created_tmp_disk_tables / Created_tmp_tables > 10% | P3 |
日志告警
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| 错误日志 | 错误日志中的错误信息 | grep -i error /var/log/mysqld.log | 出现 ERROR 级别日志 | P2 |
| 二进制日志大小 | 二进制日志文件大小 | SHOW BINARY LOGS; | 单个文件 > 1G | P4 |
| 慢查询日志增长 | 慢查询日志增长速度 | du -sh /var/log/mysql-slow.log | 每日增长 > 1G | P3 |
复制告警
| 指标 | 描述 | 监控命令 | 告警阈值 | 级别 |
|---|---|---|---|---|
| 主从延迟 | 从库延迟主库的秒数 | SHOW SLAVE STATUS\G(Seconds_Behind_Master) | > 30 秒 | P2 |
| 复制队列大小 | 中继日志队列大小 | SHOW GLOBAL STATUS LIKE 'Slave_queue_length'; | > 1000 | P3 |
| 复制错误 | 复制过程中的错误 | SHOW SLAVE STATUS\G(Last_IO_Error, Last_SQL_Error) | 任何错误信息 | P1 |
告警配置示例
Prometheus + Alertmanager 告警规则
配置 Prometheus 告警规则
编辑 mysql_alerts.yml:
yaml
groups:
- name: mysql_alerts
rules:
# 1. 可用性告警
- alert: MySQLDown
expr: mysql_up == 0
for: 30s
labels:
severity: critical
level: P1
annotations:
summary: MySQL 服务不可用
description: MySQL 实例 {{ $labels.instance }} 已停止运行超过 30 秒
- alert: MySQLReplicationBroken
expr: mysql_slave_status_slave_sql_running != 1 or mysql_slave_status_slave_io_running != 1
for: 30s
labels:
severity: critical
level: P1
annotations:
summary: MySQL 复制中断
description: MySQL 实例 {{ $labels.instance }} 的复制已中断
# 2. 连接告警
- alert: MySQLHighConnectionUsage
expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100 > 80
for: 1m
labels:
severity: warning
level: P2
annotations:
summary: MySQL 连接使用率高
description: MySQL 实例 {{ $labels.instance }} 连接使用率达到 {{ $value | printf "%.2f" }}%
- alert: MySQLRejectedConnections
expr: rate(mysql_global_status_threads_rejected[5m]) > 0
for: 1m
labels:
severity: warning
level: P2
annotations:
summary: MySQL 连接被拒绝
description: MySQL 实例 {{ $labels.instance }} 拒绝了 {{ $value }} 个连接
# 3. 性能告警
- alert: MySQLHighSlowQueries
expr: rate(mysql_global_status_slow_queries[5m]) > 10
for: 1m
labels:
severity: warning
level: P2
annotations:
summary: MySQL 慢查询数高
description: MySQL 实例 {{ $labels.instance }} 每秒慢查询数达到 {{ $value }}
- alert: MySQLInnoDBDeadlocks
expr: rate(mysql_global_status_innodb_deadlocks[5m]) > 0
for: 1m
labels:
severity: warning
level: P3
annotations:
summary: MySQL 发生死锁
description: MySQL 实例 {{ $labels.instance }} 每秒发生 {{ $value }} 次死锁
# 4. 资源告警
- alert: MySQLDiskSpaceLow
expr: mysql_global_variables_innodb_data_file_path != '' and (mysql_global_status_innodb_data_fsyncs / mysql_global_status_innodb_data_writes) > 0.9
for: 10m
labels:
severity: warning
level: P3
annotations:
summary: MySQL 磁盘空间不足
description: MySQL 实例 {{ $labels.instance }} 磁盘空间使用率高
- alert: MySQLBufferPoolHitRateLow
expr: (1 - (mysql_global_status_innodb_buffer_pool_reads / mysql_global_status_innodb_buffer_pool_read_requests)) * 100 < 95
for: 5m
labels:
severity: warning
level: P3
annotations:
summary: MySQL 缓冲池命中率低
description: MySQL 实例 {{ $labels.instance }} 缓冲池命中率为 {{ $value | printf "%.2f" }}%
# 5. 复制告警
- alert: MySQLReplicationLag
expr: mysql_slave_status_seconds_behind_master > 30
for: 1m
labels:
severity: warning
level: P2
annotations:
summary: MySQL 复制延迟大
description: MySQL 实例 {{ $labels.instance }} 复制延迟达到 {{ $value }} 秒配置 Alertmanager
编辑 alertmanager.yml:
yaml
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.example.com:587'
smtp_from: 'prometheus@example.com'
smtp_auth_username: 'prometheus'
smtp_auth_password: 'SmtpPassword1!'
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 1h
receiver: 'team-dba'
routes:
- match:
level: P1
receiver: 'team-dba-p1'
repeat_interval: 5m
- match:
level: P2
receiver: 'team-dba-p2'
repeat_interval: 15m
receivers:
- name: 'team-dba'
email_configs:
- to: 'dba@example.com'
send_resolved: true
webhook_configs:
- url: 'https://hooks.example.com/alertmanager'
- name: 'team-dba-p1'
email_configs:
- to: 'dba@example.com'
send_resolved: true
pagerduty_configs:
- service_key: 'pagerduty-p1-key'
send_resolved: true
webhook_configs:
- url: 'https://hooks.example.com/alertmanager-p1'
- name: 'team-dba-p2'
email_configs:
- to: 'dba@example.com'
send_resolved: true
webhook_configs:
- url: 'https://hooks.example.com/alertmanager-p2'
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'cluster', 'service']Zabbix 告警配置
创建告警媒介
- 进入 Zabbix Web 界面,选择 "Administration" > "Media types"
- 点击 "Create media type"
- 选择类型(如 Email、SMS 等)
- 配置相关参数
- 点击 "Update"
配置用户告警媒介
- 选择 "Administration" > "Users"
- 选择用户,点击 "Media"
- 点击 "Add"
- 选择媒介类型,配置收件人
- 点击 "Add"
- 点击 "Update"
创建触发器
- 选择 "Configuration" > "Hosts"
- 选择主机,点击 "Triggers"
- 点击 "Create trigger"
- 配置触发器名称、表达式、优先级等
- 点击 "Add"
示例触发器表达式:
- MySQL 服务停止:
{MySQL:mysql.ping.nodata(30s)}=1(P1) - 连接数高:
{MySQL:mysql.status[Threads_connected].last()}/{MySQL:mysql.variables[max_connections].last()}*100>80(P2) - 慢查询多:
{MySQL:mysql.status[Slow_queries].delta(5m)}>50(P2) - 主从延迟大:
{MySQL:mysql.slave_status[Seconds_Behind_Master].last()}>30(P2)
告警最佳实践
告警信息设计
告警信息应包含以下关键信息:
- 告警级别:P1/P2/P3/P4
- 告警名称:清晰描述问题
- 告警时间:精确到秒
- 告警对象:具体的 MySQL 实例
- 告警指标:触发告警的指标
- 当前值:指标的当前值
- 阈值:告警阈值
- 告警描述:详细描述问题
- 可能原因:可能的故障原因
- 建议操作:建议的处理步骤
示例告警信息:
[P2 告警] MySQL 连接使用率高
时间:2023-10-05 14:30:00
实例:192.168.1.101:3306
指标:Threads_connected
当前值:1600
阈值:> 1600(max_connections 的 80%)
描述:MySQL 实例 192.168.1.101:3306 的连接使用率达到 80%,可能影响新连接建立
可能原因:1. 应用连接数增加 2. 连接泄漏 3. 长连接未释放
建议操作:1. 检查应用连接池配置 2. 查看慢查询日志 3. 考虑增加 max_connections告警抑制
告警抑制可以避免告警风暴,提高告警的有效性:
- 同类型告警抑制:同一类型的告警只发送一次
- 父子关系抑制:父告警触发时,抑制子告警
- 时间抑制:短时间内相同告警只发送一次
- 告警聚合:将多个相关告警聚合为一个
告警升级
告警升级确保问题能够得到及时处理:
| 级别 | 初始通知 | 第一次升级 | 第二次升级 |
|---|---|---|---|
| P1 | 短信 + 邮件 + 即时通讯 | 5 分钟未确认,电话通知 | 15 分钟未解决,升级到上级领导 |
| P2 | 短信 + 邮件 + 即时通讯 | 30 分钟未确认,电话通知 | 1 小时未解决,升级到上级领导 |
| P3 | 邮件 + 即时通讯 | 2 小时未确认,短信通知 | 4 小时未解决,电话通知 |
| P4 | 邮件 | 1 天未处理,短信通知 | 3 天未处理,升级到上级领导 |
告警统计与分析
定期对告警进行统计和分析,可以优化告警策略:
- 告警数量统计:按级别、类型、时间段统计
- 告警触发原因分析:找出常见问题
- 告警处理时间统计:评估运维效率
- 误报率分析:优化告警阈值
- 告警抑制效果分析:调整抑制规则
示例告警统计报告:
| 月份 | P1 告警 | P2 告警 | P3 告警 | P4 告警 | 误报率 | 平均处理时间 |
|---|---|---|---|---|---|---|
| 1 月 | 2 | 15 | 45 | 120 | 5% | 30 分钟 |
| 2 月 | 1 | 12 | 38 | 110 | 3% | 25 分钟 |
| 3 月 | 0 | 8 | 32 | 95 | 2% | 20 分钟 |
故障处理流程
故障处理步骤
- 告警接收:通过多种渠道接收告警
- 告警确认:确认告警真实性,避免误报
- 故障定位:使用监控工具定位问题
- 故障处理:根据故障类型采取相应措施
- 故障验证:验证故障是否解决
- 告警关闭:关闭已解决的告警
- 故障复盘:分析故障原因,提出改进措施
常见故障处理方法
| 故障类型 | 处理方法 |
|---|---|
| MySQL 服务停止 | 1. 查看错误日志 2. 检查磁盘空间 3. 检查内存使用 4. 重启服务 |
| 复制中断 | 1. 查看复制错误 2. 根据错误类型修复 3. 重启复制 |
| 连接数满 | 1. 查看慢查询 2. 检查连接泄漏 3. 临时增加 max_connections 4. 优化查询 |
| 慢查询突增 | 1. 查看慢查询日志 2. 分析执行计划 3. 优化索引或查询 4. 考虑读写分离 |
| 主从延迟大 | 1. 检查从库性能 2. 优化复制配置 3. 考虑并行复制 4. 增加从库资源 |
总结
MySQL 告警策略和故障分级是数据库运维的重要组成部分,通过合理的告警设计和故障分级,可以提高数据库的可用性和可靠性,减少业务损失。
在实际运维中,应根据业务需求和系统规模,不断优化告警策略,提高告警的准确性和有效性。同时,定期进行故障演练和复盘,提高运维团队的应急处理能力。
通过本文的介绍,您应该掌握了 MySQL 告警策略的设计原则、故障分级方法、告警配置示例和最佳实践,能够根据实际需求设计和实施有效的告警策略。
