
先说个真实场景。凌晨两点四十七分电话响了不是闹钟是值班告警MySQL主从延迟飙到3000秒业务侧开始报写超时。你爬起来开电脑、连跳板、查复制状态、看慢日志、找误操作忙到天亮才恢复还不敢保证下次不犯。这套流程干过几次谁都会想一个问题MySQL运维为什么总是这种救火模式明明很多故障是有先兆的很多操作是可以提前预案的。这五年我带团队维护过的MySQL实例加起来快两千个了从单机到一主多从、从自建机房到云上托管都碰过。踩坑踩多了手里的工具箱也从最初的一把mysql命令行慢慢攒成了几套能自己干活的东西。今天把这套东西里最值得抄作业的5款工具和对应的思路分享出来不整虚的只说怎么让你从半夜救火变成白天就把火灭了。1. 先说痛点你的夜班为什么总被MySQL叫醒1.1 凌晨三点被电话叫醒的场景我复盘过手下运维同学的夜班工单发现95%的夜间故障都逃不出这几类磁盘空间被打满、慢查询把CPU拖死、主从同步中断且无人发现、连接数被某条SQL瞬间吃光、以及大表DDL把业务卡住。这五个问题有一个共同点——它们都不是“突然爆炸”的而是提前有征兆的只是你没在征兆出现时收到通知。比如磁盘大部分监控系统一直在查但默认只按70%、80%这种阈值报警。可一台400G的实例如果业务旺期每天涨20G你80%阈值报警时其实只剩80G可用了按这个速度四天就满。白天没人处理晚上自然炸。再比如主从延迟很多团队延迟阈值设的是60秒但夜间批量任务一跑就是几百秒报警根本没发出等业务发现时已经晚了。1.2 被动救火的老路走不通传统运维思路是“人盯着机器”问题出来再去处理。这套路在实例少、业务简单时勉强够用但实例一多必然失效。一个人盯20台数据库不可能每个指标都看到等你能看到时问题通常已经影响业务了。我常说运维核心不是“反应快”而是“提前量”。把故障消灭在预警阶段比练就一身快速修复的本事有价值得多。所以整套工具链的设计目标就一个让机器自己发现问题、自己执行预案实在搞不定再喊你。这套思路落实下来就是下面这五款东西。2. 神器一pt-query-digest专治各种慢SQL2.1 慢查询日志怎么开才不浪费性能MySQL自带慢查询日志但很多人不会开。常见的错误是为了省事把long_query_time设为0相当于记录所有查询日志瞬间膨胀磁盘IO都被拖垮了。我的经验是先设个比较宽容的阈值比如2秒跑上一周看看数据再根据实际业务往下调。生产环境我的推荐配置是这样[mysqld] slow_query_log ON slow_query_log_file /var/log/mysql/slow.log long_query_time 1 log_queries_not_using_indexes ON min_examined_row_limit 1000log_queries_not_using_indexes专门抓那些没走索引的全表扫描这对OLTP系统特别关键。注意它有一个坑很多ORM框架生成的查询本来就不该走索引比如小表查询开了这个参数会把慢日志刷爆。所以我还加了min_examined_row_limit 1000只记录扫描超过1000行的查询过滤掉那些“小表全扫无所谓”的噪音。2.2 一次CPU打满的排查实录光有日志还不够日志是文本几十万行没法直接看。早期我排查CPU打满问题都是把慢日志拖下来然后用awk去统计费时费力还容易漏。后来换成了pt-query-digest一条命令就能把混乱的慢查询日志整理成层次分明的报告。pt-query-digest是Percona Toolkit里的核心工具实测效果确实好。它的用法很简单wget https://downloads.percona.com/downloads/percona-toolkit/LATEST/binary/debian/x86_64/percona-toolkit_3.5.7-1.jammy_amd64.deb # 或 RPM 发行版使用 yum 安装 percona-toolkit 包 pt-query-digest /var/log/mysql/slow.log /tmp/report.txt生成的文件里上半部分是总览表按查询的“总耗时占比”排序一下就能看出哪些SQL才是罪魁祸首中段是每个查询的详细统计包括执行次数、平均耗时、响应时间分布最后还附带了完整的SQL语句样本。有一次凌晨CPU报警我用它分析不到一分钟就定位到一条对三千万行的大表做排序的SQL而且这个SQL刚上线还不到三天。当晚就把问题SQL发给开发加了个联合索引CPU直接降下来。2.3 分析报告怎么读才不会被带偏用pt-query-digest有个容易误判的地方它默认按“总执行时间”排序但总时间高不代表单次慢。有些SQL跑了1000次每次200ms加起来很显眼但业务能够接受有些SQL一天才跑两次平均耗时要8秒却因为执行次数少排到了后面这种往往是批量任务一旦失败影响很大。我的建议是看报告时同时关注两个维度高频率的查询可能是漏索引或接口被刷和高单次耗时的查询可能是核心链路里的隐藏炸弹。实际做法是对同一份报告跑两次一次用默认排序一次加--order-by Query_time:max按最大单次耗时看。这样两头都能抓住。这里还要补充一点pt-query-digest不仅能分析慢查询日志还能直接连库抓当前正在执行的查询pt-query-digest --processlist h192.168.1.10,umonitor,pyourpass --interval1这个模式相当于给运行中的数据库做“实时体检”特别适合复盘线上突发卡顿。3. 神器二Percona Toolkit里的几条救命命令3.1 pt-online-schema-change大表加字段不再锁库MySQL的原生DDL有个老问题INPLACE策略下很多操作还是要锁表而大表的DDL一旦执行波及面就是整个业务。我见过一次事故某电商在订单表大约2亿行上加了一个普通索引直接在凌晨把主库拖到几近瘫痪业务侧的写入全部卡住执行了20多分钟才被运维kill掉。真正安全的做法是使用pt-online-schema-change简称pt-osc。它的思路是创建一张与原表结构相同的空表把DDL先应用到空表上然后分批把原表数据拷贝到新表拷贝过程中通过触发器把新增的写操作也同步到新表最后在业务低峰期做一次原子性换表。操作示例pt-online-schema-change \ --alterADD INDEX idx_user_id(user_id) \ Dshop,torders \ --host192.168.1.10 \ --userdba \ --passwordyourpass \ --max-lag5 \ --check-interval2 \ --execute注意我给的关键参数--max-lag5表示主从延迟超过5秒就暂停拷贝避免给主库和从库带来过大复制压力--check-interval2是检查延迟的间隔。不用pt-osc的同学务必记住绝对不要在业务高峰期裸跑DDL。3.2 pt-slave-restart复制中断的快速恢复主从复制中断是MySQL运维最常见的夜间噩梦。瓶颈出现在1062主键重复和1032记录不存在这两个错误码上。传统做法是登录从库手工找到出错事务、手动跳过一个晚上折腾N次第二天黑着眼圈上班。pt-slave-restart可以自动化处理这个流程。它的典型参数pt-slave-restart h192.168.1.11,uadmin,pyourpass \ --error-numbers1062,1032 \ --skip-count10 \ --sleep3这条命令的含义是当从库复制线程因为1062或1032错误中断时自动跳过错误并重启复制线程最多连续跳过10次如果第11次还是同样错误则停止等待人工介入。这个策略既能把临时性的脏数据跳过又能在问题顽固时不至于无限跳过导致数据严重不一致。3.3 pt-kill连接数爆满时的快速止血连接数被打满是另一类高发问题。通常是某条SQL全表扫描、某个连接池配置不当瞬间把max_connections打满后续所有连接排长队看起来像数据库死了。遇到这种情况你要做的第一件事是快速杀掉源头。pt-kill可以按条件批量杀连接比人肉去information_schema.processlist里一条条挑效率高得多pt-kill host192.168.1.10,uadmin,pyourpass \ --busy-time30 \ --match-commandQuery \ --victimsall \ --kill意思是杀掉所有执行时间超过30秒的查询。这条命令在某些场景下有点激进所以我通常把它放在监控告警触发后的应急预案里而不是常驻执行。真正频繁跑慢查询的库还得靠前面的pt-query-digest把病根挖出来。4. 神器三MySQL监控铁三角让故障在发生前报警4.1 监控体系的基础组件选型说到监控目前MySQL生态最成熟的一套组合是Prometheus mysqld_exporter Grafana。这套组合的优势是社区生态成熟、配置灵活、告警规则可以做得非常细。很多云厂商自带的监控虽然好用但黑盒出了问题你连指标口径都说不清楚。自建监控则能完全掌控。关键指标我分四组梳理分类核心指标预警阈值参考资源类磁盘空间使用率、磁盘IO读写延迟磁盘使用率超过80% 且连续15分钟性能类QPS/TPS、Threads_running、Innodb_rows_readThreads_running连续5分钟超过50复制类Seconds_Behind_Master主从延迟、Slave_IO_Running、Slave_SQL_Running延迟超过30秒告警按业务调整连接类Threads_connected、Max_used_connections连接数超过max_connections的70%很多团队只盯着磁盘和CPU忽略了Threads_running这种最直接反映“数据库是否卡死”的指标。线程运行数暴增往往早于CPU打满它才是让你“提前五分钟”的关键。4.2 Prometheus配置和告警规则怎么落地mysqld_exporter部署很简单下载对应平台二进制用--config.my-cnf指定一个只读账号的连接配置再把:9104端口挂到Prometheus抓取目标里。抓取周期我设为10秒太密会额外增加数据库负担太疏又会错过峰值。告警规则才是重点。我见过很“闹腾”的告警体系每天几百条警报值班同学看久了直接免疫最后真正的大事反而被淹没。我的原则是告警必须能直接指导行动宁可少而精不可多而杂。下面是一条我实际在用的规则- alert: MysqlThreadsRunningHigh expr: mysql_global_status_threads_running 80 for: 5m labels: severity: page annotations: summary: 数据库高并发运行告警 description: 运行线程数已超过80持续5分钟请检查慢SQL与连接池配置注意我加了for: 5m。这个字段的意义是连续五分钟满足条件才触发而不是瞬时抖动立刻报警。短促的并发高峰很常见直接告警只会培养“这又是误报”的潜意识。真正需要被叫醒的是持续恶化的事件。4.3 部署监控时的一个易踩坑mysqld_exporter默认会采集一大堆指标某些版本会因为在慢查询日志表上跑统计查询反而给数据库带来额外压力。这个问题在监控大量实例时尤其明显。我的做法是在采集配置里关闭不必要的采集项--no-collect.perf_schema.events_waits \ --no-collect.perf_schema.file_events \ --no-collect.auto_increment \只保留真正关注的指标采集器本身的CPU占用能降一个量级。另外一个坑和权限有关监控账号至少需要PROCESS, REPLICATION CLIENT, SELECT三个权限否则主从延迟和连接相关指标会全部为空。很多同学部署完看不到数据第一反应是防火墙结果发现其实是权限没给够。5. 神器四Orchestrator高可用切换主库挂了立刻有人顶5.1 手动切换为什么让你熬大夜主库宕机是MySQL运维“压轴级”的噩梦。传统手动切换流程是这样发现主库挂了确认是否有半同步备库选择一个数据最新的从库修改配置文件开启只读执行change master to再让业务侧改连接地址或切换VIP。看起来简单但真到凌晨两三点执行每一步都可能出幺蛾子可能是从库延迟比你预估的高几十秒可能是中继日志没应用完也可能是某个代理连接没有断开导致数据写入冲突。手动切换最大的风险其实是“慌”。人一慌就会跳过校验步骤接库不检查数据完整性最后业务恢复后数据出现不一致比宕机本身还难收拾。我见过凌晨手动切主后主从两边数据差了十几分钟第二天花了整个白天才手工补回数据。5.2 Orchestrator帮你做了哪几件事Orchestrator简称orc是目前比较成熟的开源MySQL高可用管理工具。它能自动发现主从拓扑关系、实时检测主库健康状态并在主库故障时按预设策略选择最优从库进行提升。整个切换过程有严格的步骤记录和数据完整性校验比人工少了很多随意性。我推荐的部署模式是Orchestrator用三节点Raft模式部署在独立主机上监控所有MySQL实例应用侧通过VIP例如keepalived访问数据库切换发生后VIP自动漂移到新的主库。这样数据库层和应用层都不用改配置业务无感知。5.3 真刀真枪演练时的注意事项装了Orchestrator不代表高枕无忧。我有两个血泪教训第一Orchestrator切换后从库的read_only参数要自动置位否则新主库可能被残留的写连接污染。这个参数多数配置模板已经做了但要在演练中反复验证。第二半同步复制semi-sync replication在故障切换时是个双刃剑。开启半同步可以保证主库宕机时不丢数据但如果所有从库都异常半同步机制会让主库挂起。我生产环境的策略是使用rpl_semi_sync_master_enabledON的同时把rpl_semi_sync_master_timeout设成1000毫秒超时后降级为异步保证极端情况写业务不受阻。切换演练要常态化。我要求团队每个月做一次自动切换演练每次演练完检查三条数据有没有丢、应用有没有重连报错、告警有没有漏掉某个环节。只有演练做到“切换失败也能自动回滚”的程度你才敢在真实故障时依赖它。6. 神器五XtraBackup备份恢复把数据上双保险6.1 全备加增量的合理节奏数据库不备份出事只能去天台。但光有备份文件还不够你还需要一套能快速恢复、能按时验证的自动化体系。我用的是Percona XtraBackup物理备份工具支持在线备份、增量备份恢复速度远胜于mysqldump的逻辑备份。全备节奏我设置在每周日凌晨业务最低峰跑一次全量其余每天一次增量备份。增量备份的核心是依赖LSN序号命令长这样# 每周日全量备份 xtrabackup --backup --target-dir/backup/full \ --host192.168.1.10 --userbackup --passwordyourpass # 每天增量备份基于上一个备份目录 xtrabackup --backup --target-dir/backup/inc1 \ --incremental-basedir/backup/full \ --host192.168.1.10 --userbackup --passwordyourpass恢复流程则是先准备全备再按顺序应用增量xtrabackup --prepare --target-dir/backup/full xtrabackup --prepare --target-dir/backup/full \ --incremental-dir/backup/inc1这个命令序列很多人第一次接触会被--prepare搞晕。简单理解就是备份文件在准备之前是“不一致”的——它包含各个表在不同时间点的状态--prepare会重放事务日志把所有数据推进到同一个时间点恢复后才能当正常数据目录使用。6.2 恢复演练才是备份的灵魂有备份不演练等于没备份。这是我在一个故障中得来的教训。有次我们误删了一张大表拿备份恢复结果发现备份脚本三个月前就已经因为磁盘空间不足退出了而监控告警被其他大事件淹没了。那次恢复演练非常痛苦最后靠binlog一点一点往回补数据。从那以后我定了一条铁律每个月至少做一次恢复演练。做法是在测试环境搭一个临时实例把最近的全量备份和增量备份按真实流程恢复一次然后启动实例检查数据表数量、行数和关键业务记录再用内置的校验工具跑一遍逻辑校验。演练时间通常控制在两小时以内如果超过这个时间说明备份策略有问题——要么数据量太大恢复太慢要么中间步骤太多人工程序太重。6.3 备份文件的安全处理和常见误区备份文件的安全处理包括三方面一是传输过程加密避免备份文件在网络上裸奔二是存储位置分离不能和数据库同一块磁盘否则磁盘一起挂三是保留多份异地副本常见做法是每天把备份上传到对象存储并保留最近30天。还有一个容易忽略的点binlog也要定期备份。XtraBackup备份的是某个时间点的数据快照但如果你需要恢复到“误操作前1分钟”这种粒度就必须依赖binlog。我建议在备份策略里加上mysqlbinlog --read-from-remote-server --host127.0.0.1 \ --userbackup --passwordyourpass \ --raw --stop-never \ /backup/binlog/这条命令会持续把binlog实时拉取到备份目录里保证任何时间点都能结合全量备份做精确恢复。没有这套底层保障你就算有备份也最多只能恢复到“昨晚”而不是“一分钟前”。7. 常见问题与排查技巧实录7.1 监控告警轰炸到麻木怎么办工具链路搭起来之后第一个瓶颈是告警疲劳。我见过有团队把所有阈值的默认值都调得很敏感结果值班同学一天收几百条微信消息最后把通知渠道静音了。真正出了大故障没人第一时间响应。我处理这个问题的方法是建立分级告警机制邮件告警用来记录企业微信通知用来提醒电话/短信只留给真正需要马上处理的。同时把告警规则按业务影响分类例如磁盘使用率超过90%且持续15分钟才触发电话连接数超过80%且持续5分钟才触发电话其它一律进邮箱由日间处理。这样一来值班同学真正被电话叫醒的次数一个季度可能只有两三次每一次都是必须介入的事件。7.2 工具操作引发的次生风险工具用多了另一个风险是“工具自身成了事故源”。比如pt-online-schema-change如果触发器创建失败会在原表上留下残余僵尸触发器下次业务写入时多一层开销。再比如pt-slave-restart如果配置不当无限跳过错误主从数据不一致程度只会越来越大。所以我给所有工具设了一条使用红线工具只做辅助判断重大操作前必须人工复核。执行DDL之前先确认数据量、预留磁盘空间、评估执行时间批量kill之前先连接只读从库复现问题确认哪些连接是安全的。工具链条缩短了你的反应时间但不意味着你可以省掉判断。7.3 冷静的心态和规范化的操作才是最终兜底说到底工具无法消灭所有故障。你早晚会遇到一种情况所有监控都正常、所有工具都跑了一遍但数据库就是响应异常。这种时候真正救你的是熟练度和冷静。我常年要求在应急预案里把每一步操作都写成可执行的命令清单并且规定夜间紧急操作必须两人确认一人执行一人复核。这个规矩看似拖慢速度实际上大大减少了误操作导致的二次事故。最后分享一点个人心得这五年我和MySQL打了太多交道从最初的手动救火、半夜翻日志到现在的监控告警、自动切换、定期演练最大的体会是运维这份工作熬夜不是勋章而是系统性失败的信号。每当你发现自己又在半夜处理一个明明可以预警和自动化的故障就应该花时间把流程补充完整而不是继续麻木地“再来一次”。这套工具链搭建之后我团队的实际效果是夜间被电话叫醒的频率从每周一两次降到了两个月一次而且被叫醒的事件基本都是无解的硬故障——硬件损坏、机房断电这类事情工具解决不了但只需要你按预案操作即可。最后再分享一个小技巧别急着把五款工具一次性全上。优先级应该是先做监控告警解决“看不到”再做慢查询分析解决“查不动”然后上备份恢复体系解决“保不住”最后才考虑在线DDL和高可用自动切换解决“改不了”和“切不动”。一步一步来等每个环节都跑顺了你自然会感受到什么叫“再也不用熬大夜”。