事情还得从上个月说起。我手头维护的那套业务库里有几台 MySQL 5.7 实例已经超龄服役很久了。监控后台每隔几天就弹一次版本过期的提示群里的小伙伴一看到这种告警就开始互相甩锅——EOL 了升级吗没预算先扛着吧。说实话MySQL 5.7 走到生命周期尽头这件事技术圈里早就不是新闻了可真正落到你负责的数据库上那种焦虑是完全不一样的。尤其是随着 8.0 的非 LTS 创新版节奏越来越快以及 8.4 这一条新 LTS 主线已经出现摆在大多数团队面前的其实根本不是要不要升级而是升级到哪个版本、怎么平稳升级、途中会踩到哪些雷。这篇内容就是我这次从 MySQL 5.7/8.0 向 MySQL 8.4 升级的完整记录包括 EOL 背景下的版本选型逻辑、升级前的体检清单、正式切换的操作细节以及升级后撞上一个官方 Bug 的完整排查链路。整个过程谈不上多惊心动魄但踩过的坑、绕过的弯、最终确认是官方问题的那种终于松了口气的心路历程我觉得都值得分享出来。如果你也正在为 MySQL 8.4 升级做准备或者在犹豫要不要升级、怎么排期这篇文章应该能帮你省下不少试错成本。1. 为什么是 8.4EOL 节点带来的选择题1.1 先看时间线5.7 和 8.0 到底急不急MySQL 社区版的维护节奏很多人直到升级前都没彻底弄明白。简单来说MySQL 5.7 在 2023 年 10 月就已经到达生命周期终点意味着社区版不再有常规的 bug 修复和安全补丁。虽然有的云厂商或者付费订阅还能提供延保但那本质上是在用商业合同帮你续命一旦合同到期或者厂商策略调整你手上的老版本就真的裸奔了。MySQL 8.0 的情况稍微特殊一点它原本也有一张 EOL 的时间表但后续因为各种原因官方把维护终点做了一定延长。这里我不打算纠缠具体年月大家只要记住一个核心逻辑8.0 这条产品线的定位是创新版也就是功能迭代快、发布节奏快但长期维护承诺不如 LTS 版本清晰。而 MySQL 8.4 是官方重新划分产品线之后首条 LTSLong Term Support版本它的维护周期更长更适合企业级生产环境。说白了当 5.7 已经彻底退场、8.0 逐渐走向新功能试验田定位的时候8.4 就是那个长期饭票。我当时的判断很简单与其在一个快要进入维护尾声的版本上反复横跳不如直接瞄准 8.4一次性把升级路线定在一条稳定的 LTS 主线上。1.2 为什么我不建议守着 8.0 不动8.0 当然不是不能用它已经经历了多个小版本的打磨稳定性非常不错。但这里有个容易被忽略的问题如果你现在是从 5.7 升到 8.0那你两年后大概率还得再来一次升级因为 8.0 后续的维护承诺并不像 LTS 那样让人安心。升级这件事最贵的从来不是软件授权费而是人力成本、业务适配成本、回归测试成本以及半夜钉钉群里数据库连不上了的惊恐三分钟。所以我在选型阶段就定下了一个原则一步到位升级到 MySQL 8.4 LTS。这样未来三到五年内我都不用再为这个版本还安不安全、官方还管不管这类问题操心了。MySQL 8.4 相比 8.0 也做了一些默认行为和参数层面的优化比如更严格的密码认证插件默认策略、更规范的错误日志体系以及对一些旧参数的清理。这些变化在带来安全提升的同时也意味着升级不是简单换一个二进制文件就能搞定的你需要认真对待每一条不兼容变更。1.3 升级前先给自己算的三笔账在正式动手之前我建议大家先别急着下载安装包先把三笔账算清楚第一笔是存量资产的账。你到底有多少台实例、每台实例上有多少个库、最大的表有多大、有没有用到存储过程、触发器和自定义函数、有没有老版本特有的参数配置这些信息决定了升级的工作量和风险边界。第二笔是兼容性的账。MySQL 8.4 移除了部分在 8.0 早期就标记为废弃的功能特性比如 mysql_native_password 的默认禁用、部分旧 SQL 语法的行为变化。如果你的业务代码里还带着老旧的连接字符串或者特殊语法升级之后很容易出现能启动但连不上或者能连上但跑不动的尴尬局面。第三笔是回滚能力的账。升级不是只能进不能退但回滚的难度跟你在升级前做了多少准备成正比。没有全量备份、没有保留旧版本的完整配置、没有做过恢复演练那么所谓的回滚预案基本是句空话。这三笔账算完你对升级的焦虑应该就能转化为一张任务清单了。2. 升级前哨把不会出问题变成可验证的清单2.1 我们实际执行的兼容性检查升级这件事最怕的就是我觉得没问题。我们当时的做法是专门搞了一个兼容性检查阶段哪怕业务方催得再急这个步骤也绝对不能省。首先是用官方工具或脚本扫描所有实例的配置项重点排查那些在 MySQL 8.4 里已经删除或改名的参数。比如 8.4 里日志系统的参数从 log_warnings 改为 log_error_verbosity如果你沿用旧参数轻则告警刷屏重则启动失败。我们还检查了所有用户的认证插件确认没有依赖 mysql_native_password 的存量账号——这一步非常关键因为 8.4 默认已经不再支持这种旧式认证机制如果你的中间件或者老客户端不支持 caching_sha2_password升级后就会出现大量认证失败。其次是 SQL 层面的回归。我们把业务侧的慢查询日志、审计日志都拉了出来整理出一份高频 SQL 清单在测试环境的 MySQL 8.4 实例上逐条跑了一遍。有些 SQL 在 5.7 里能正常执行到 8.4 会因为优化器行为变化而选择完全不同的执行计划。不是说新的执行计划一定更差但你必须提前知道否则上线后突然冒出来的慢查询会让你措手不及。最后是检查插件和系统表。MySQL 8.4 不再需要 mysql_upgrade 这个传统步骤因为数据字典升级会在启动时自动完成。但这也意味着你必须提前确认磁盘空间充足、系统表没有损坏。我们就在一台测试机上遇到过因为 binlog 文件占满磁盘导致启动时数据字典升级中断的幺蛾子。2.2 备份策略与恢复演练不能走过场升级前的全量备份谁都会做但很多人做完备份就再也不管了直到出问题时才后悔——备份文件能不能用、恢复流程要走多久、恢复后数据是否一致这些都必须提前验证。我的建议是至少在测试环境做一次完整的备份恢复演练并且要在恢复出来的实例上跑一遍核心接口的冒烟测试。光有 dump 文件是不够的你要确保备份链路本身是通的。我们当时用的是物理备份加 binlog 增量归档的组合方案在演练中模拟了备份库被误删、恢复到故障前一秒的场景全程跑完大概花了一个多小时。这个时间数据等能让你心里真正有底。2.3 跨版本升级路径怎么走还有一个特别容易被忽略的细节从 5.7 直接跳到 8.4 是不被官方推荐的跨大版本升级路径。稳妥的做法是先升级到 8.0 的最新小版本确认数据字典和表结构完成升级后再往 8.4 走。这不是多此一举而是因为 8.4 的数据字典结构建立在 8.0 的演进基础上跳过中间版本风险太高。我们当时因为部分实例本来就是 8.0所以少走了一段路。但有 5.7 老实例的同事确实按照5.7 - 8.0.x - 8.4的两步走方式操作的每一步都做一次数据字典升级和业务验证。听上去麻烦但事后证明这个稳扎稳打的做法非常值得因为每一步的差异都比较好定位。3. 正式升级的执行细节从预检、替换到切换3.1 停机窗口怎么安排才不慌升级总归要有一个窗口期关键是窗口期怎么留。我们的做法是选择业务低峰期的凌晨并且把窗口长度设定为预计操作时间的两倍以上。比如预估切换需要两个小时那窗口就按四个小时申请多出来的时间用来做紧急排障和回滚。窗口前两小时我们还要做一轮最终的预检确认所有从库追上了主库、延迟为 0确认 binlog 没有异常堆积确认备份文件已经完整拷贝到独立存储。预检通过后才真正进入操作流程。3.2 主从切换式的升级步骤升级方式上我强烈建议不要在主库上原地升级除非你的业务量非常小、可以接受长时间停机。我们用的是先升级从库、再主从切换的方案。具体步骤大致是这样的在从库上停掉复制服务把新版本的二进制包解压替换到位启动从库实例让 MySQL 自动完成数据字典升级检查错误日志确认没有致命错误后重新拉起复制观察新版本从库的复制状态、延迟、错误日志至少稳住一个小时在主库配置不变的情况下把读写流量切到新版本从库上原主库降级为新从库或备用节点原实例再按同样流程升级重新接入集群。这个方案的好处在于任何一步不对劲流量还能切回去不需要面对已经升级到一半、业务完全停摆的绝望局面。3.3 升级后的第一轮验证清单切换完成后别急着收工我总结了一个升级后三件事的清单每次都用得上第一件事核对版本和全局变量。SELECT VERSION() 必须是指定的小版本号关键参数如 transaction_isolation、innodb_buffer_pool_size、max_connections 要和预期一致。配置文件里的废弃参数是否被正常忽略也要看日志确认。第二件事检查所有账号的认证插件和权限。8.4 对权限表的校验更严格有些旧账号可能因为认证插件不受支持而失联。我们当时就发现一个老应用账号连不上了后来重新创建账号并授权才恢复这个坑如果你不提前排查切换后的电话会被打爆。第三件事做一轮核心业务 SQL 的压测。不需要全量但一定要覆盖读多写少、事务写、批量导入这三类典型场景。通过对比升级前后的延迟曲线和慢查询分布基本就能判断新版本在你的业务模型下是否正常。4. 深度踩坑一个官方 Bug 的完整排查链路4.1 现象先是复制延迟然后是错误结果升级后的第一周一切安静得让人有点不踏实。直到某天下午监控告警突然弹出一条消息某从库的 SQL 线程报错复制延迟开始持续堆积。我当时第一反应是不会升级的时候把 binlog 搞出问题了吧于是赶紧登录从库查看 error log结果只看到两条非常笼统的提示大意是执行某个事件失败和一个外键关联相关的报错。这里要说明一下业务背景。我们有一个统计类业务会定期从主业务库同步数据到报表库中间用了几张带外键约束的分表。报错指向的正是其中一张分表的更新语句提示违反外键约束。但诡异的是我手工去主库执行同样的更新语句它跑得又快又好根本不报错。而且从库的 SQL 线程一旦停下后面的 binlog 又只能干等。我们当时一度怀疑是升级过程中数据不一致导致的。4.2 第一轮排查从数据一致性开始却越查越糊涂按常规思路我想先确认主从数据是否不一致。于是用工具对那张分表做了全量校验结果竟然一切正常所有行的内容和主库完全一致。那问题来了数据没问题为什么 SQL 线程会报外键约束失败我怀疑是不是外键元数据有问题于是查看了表结构外键定义都还在指向的主表也没问题。接着我尝试在从库手动执行那条 update居然也能成功主键和外键都能对上。这下事情变得有趣了——同样是数据跑在 SQL 线程里就报错手动执行就正常。唯一合理的解释是SQL 线程在应用 binlog 事件时走了和手工执行完全不同的代码路径而这条路径恰好触发了某个逻辑错误。4.3 定位EXPLAIN 结果和官方 Bug 的吻合为了进一步确认我在从库上手工执行了和报错语句相似但加了 EXPLAIN 的查询结果赫然发现优化器选择的执行计划和主库不一样预估行数偏差非常夸张甚至选错了驱动表。当时我脑子里某个开关就啪地一下被打开了——这大概率不是数据问题而是优化器或者索引统计信息出了问题。我立刻去查 information_schema.STATISTICS 这类统计视图发现那张分表的统计信息存在异常的陈旧状态即使执行了 ANALYZE TABLE 和重建索引只能管一两天之后又会复发。折腾到这一步我在官方 Bug 追踪系统里搜索了 MySQL 8.4 关于 Instant 列变更、索引统计更新的相关条目果然找到一条和我们场景高度吻合的官方确认问题在特定条件下执行在线 DDL快速加列之后表上的二级索引统计信息可能长时间不刷新导致优化器生成错误计划在复制 SQL 线程的回放路径上甚至表现为串行执行同一行时出现逻辑错误。官方 Bug 确认后我反而松了口气因为这意味着问题不是我们数据坏掉或者操作失误而是一个上游版本的已知缺陷。随后我们按照官方给出的指引先给从库的异常 SQL 强制指定了索引恢复复制再在下一个维护窗口把实例升级到包含修复的补丁小版本。补丁升级后我们连续观察了两周那条 SQL 的执行计划恢复稳定复制延迟也降到了毫秒级。4.4 这段排查给我留下的经验这次排查前后花了将近三天复盘下来有几条经验很值钱第一遇到数据一样但结果不一样的问题优先怀疑优化器和统计信息而不是一上来就抄起一致性校验工具穷跑一遍。因为如果逻辑层一致物理层几乎不可能自己坏掉。第二EXPLAIN 是你的好朋友但不只是在写 SQL 的时候用。当复制回放报错时同样可以拿报错的那条日志去目标库上手动执行并对比计划差异。第三官方 Bug 不是洪水猛兽反而是一根救命稻草。对小团队来说能和官方行为对得上意味着你不需要自己去研究那些深不可测的 InnoDB 内部逻辑等补丁就行了。当然等补丁不等于裸奔等临时用 force index、修改 SQL 方式绕过是必须同时做的。5. 升级后的稳定性运营与回滚预案5.1 升级后一周重点盯的监控指标升级后的一周我建议把监控粒度调得更细一些。除了常规的 CPU、内存、磁盘和连接数之外有几个指标特别值得盯第一个是复制延迟。主从延迟突然拉高往往不是网络问题而是新版本在某个特殊负载下出现了性能回退或者 bug。我们这次如果不是一直盯着延迟曲线那个 SQL 线程的报错可能还要晚几个小时才会被发现。第二个是锁等待和死锁。8.4 的事务调度和行锁实现虽然沿用了 InnoDB 的成熟机制但和旧版本仍可能存在细微差异尤其是并发写多的业务要留意锁等待直方图的变化。第三个是慢查询分布。升级后执行计划的改变会让一些原本很快的 SQL 突然变慢。监控里不能只看慢查询总数还要看 TOP N 和耗时分布每天对比一次连续一周基本就能把异常暴露完。5.2 回滚不是不行就回那么简单回滚预案很多人写了但真到要用的时候才发现漏洞百出。比如你升级完成后新版本继续写了新的 binlog旧版本的实例即使还留着也没有办法直接接手这些新数据。所以回滚预案的核心不只是把程序换回去还要考虑数据回放和数据一致性。我们当时的做法是保留一套未升级的旧版本从库也就是常说的金丝雀节点在整个观察期内让它一直作为只读备机存在持续接收主库的 binlog 备份但不回放。一旦新版本出了问题我们就把它作为替换节点配合备份增量恢复把业务切回去。这个方案听起来奢侈但能最大程度地保住数据可用性。5.3 长线配置调整从默认值到贴合业务升级到 8.4 之后别急着把所有参数调成高性能模式。我们遇到过不少团队升级后马上把 buffer pool 调到很大、把 binlog 刷盘策略改成最激进模式结果性能没提升反而出现大量的 IO 抖动。我的建议是先用默认参数跑两三天让统计数据和业务负载回归正常再基于监控数据做渐进式调整。比如 innodb_buffer_pool_size可以按实际命中率来调binlog 相关参数可以根据同步延迟和磁盘 IO 负载来调整连接数则按峰值并发和连接复用率来设置。记住一个原则8.4 的默认值已经是一个很合理的起跑线你的业务给了我充足的数据再去动参数而不是照搬网上流传的通用模板。升级到 MySQL 8.4 这件事回头看起来真正难的不是那几行升级命令而是升级前后的细致观察和快速排障能力。如果你也正在准备升级我给各位最真诚的建议就是给足时间、做足演练、预留回滚然后大胆地往前走。官方 Bug 别怕它有补丁EOL 焦虑也别怕LTS 版本就在那里等着你。把这次踩坑记录下来下一次升级你的底气绝对不一样。
阅读完成 · 觉得有帮助?