最近,我们团队把数据库从MySQL 5.7升级到了MySQL 8.4 LTS。
这个过程,比我想象的要艰难得多。从最开始的"不就是升个级吗",到中间的"这也不行那也不行",再到最后的"终于搞定了",前前后后折腾了一个多月,踩了无数的坑。
这篇文章就来聊聊这段经历,从升级前的准备、升级过程中的坑、到升级后的优化,说说MySQL 8.4 LTS到底怎么样,以及我们是怎么从"入门"到差点"放弃",最后又坚持下来的。
为什么要升级
先说说为什么要升级。
我们的数据库一直用的是MySQL 5.7,用了很多年,一直很稳定。但MySQL 5.7的官方支持在2023年10月就结束了,不再有安全更新和bug修复。继续用5.7,意味着要自己承担安全风险,而且云服务商也在逐步淘汰5.7的实例。
另外,MySQL 8.0之后有很多新特性:窗口函数、CTE、JSON功能增强、更好的性能、更强的安全特性。这些特性,在5.7上都用不了。
MySQL 8.4 LTS在2024年4月发布,是MySQL的第一个LTS(长期支持)版本,支持到2032年。对于企业用户来说,这是一个很有吸引力的选择:一次升级,长期不用再折腾。
所以,我们决定,直接从5.7跳到8.4 LTS,一步到位。
现在回头看,这个决定是对的,但过程确实很折腾。
升级前的准备
升级之前,我们做了一些准备工作。
第一,阅读官方文档。把MySQL 8.0和8.4的release notes、升级指南、兼容性说明都读了一遍,列出了所有不兼容的变更。
第二,评估应用兼容性。检查我们的应用代码,看看有没有用到5.7特有但8.4不支持的语法、函数、特性。比如,8.0之后移除了一些旧的密码认证方式,默认字符集从latin1变成了utf8mb4,SQL模式更严格了。
第三,准备测试环境。搭了一个和生产环境一样的测试环境,导入了生产数据的副本,在测试环境上先做升级演练。
第四,制定回滚方案。万一升级失败,要有回滚方案,能快速切回5.7。我们的方案是:升级前做一次全量备份,升级失败就用备份恢复,或者用主从切换的方式回滚。
准备工作做了一周,觉得应该没问题了,就开始了升级。
坑一:认证插件不兼容
第一个坑,是认证插件不兼容。
MySQL 8.0之后,默认的认证插件从mysqlnativepassword改成了cachingsha2password。我们的应用用的是比较老的MySQL驱动,不支持cachingsha2password,升级之后,应用连不上数据库,报认证错误。
这个问题,我们在准备阶段其实已经注意到了,但当时觉得改一下用户的认证插件就行。实际操作的时候,才发现没那么简单。
我们把所有用户的认证插件改回了mysqlnativepassword,应用能连上了。但新创建的用户,默认还是cachingsha2password,每次都要手动改。而且,有些第三方工具(比如旧版的Navicat、数据同步工具)也不支持新的认证插件,连接的时候各种报错。
解决方案:
- 把defaultauthenticationplugin设置成mysqlnativepassword,让新用户默认用旧的认证方式
- 升级应用的MySQL驱动到支持cachingsha2password的版本
- 逐步把用户迁移到新的认证插件,最终全部用cachingsha2password
这个坑,花了我们两天时间才彻底解决。
坑二:SQL模式更严格
第二个坑,是SQL模式更严格了。
MySQL 8.0之后,默认的SQL模式包含了ONLYFULLGROUPBY、STRICTTRANS_TABLES等更严格的模式。我们的一些老SQL,在5.7上能跑,在8.4上直接报错。
最典型的是ONLYFULLGROUP_BY。我们有一些查询,GROUP BY的字段和SELECT的字段不一致,在5.7上能跑(虽然结果可能不确定),在8.4上直接报错。
还有STRICTTRANSTABLES。插入数据的时候,如果字段长度不够,或者类型不匹配,5.7可能会截断或者警告,8.4直接报错。我们有一些老代码,插入的数据偶尔会超过字段长度,在5.7上 silently 截断了,在8.4上直接报错,导致功能异常。
解决方案:
- 全面排查SQL,修改不符合规范的查询
- 对于暂时改不了的SQL,在会话级别调整SQL模式(不推荐,只是临时方案)
- 扩大字段长度,或者在应用层做数据校验
我们花了一周时间,排查了所有的SQL,修改了几十处不符合规范的查询。这个过程虽然麻烦,但也让我们的代码更规范了。
坑三:字符集和排序规则
第三个坑,是字符集和排序规则。
MySQL 8.0之后,默认字符集从latin1变成了utf8mb4,默认排序规则从utf8mb4generalci变成了utf8mb40900ai_ci。
我们的老数据库,有的表是latin1,有的是utf8,有的是utf8mb4,排序规则也五花八门。升级之后,跨表关联查询的时候,因为字符集和排序规则不一致,报"Illegal mix of collations"错误。
还有一个问题是,utf8mb40900ai_ci是MySQL 8.0新增的排序规则,5.7不支持。升级的时候,有些表的排序规则没有正确转换,导致数据乱码或者查询异常。
解决方案:
- 统一所有表的字符集为utf8mb4,排序规则为utf8mb40900ai_ci
- 转换字符集的时候,要先备份数据,避免乱码
- 对于已经乱码的数据,需要特殊处理(比如先导出成latin1,再导入成utf8mb4)
字符集的问题,是最让人头疼的。我们有一张老表,因为字符集混乱,转换的时候数据乱码了,花了好几天才恢复。
坑四:性能变化
第四个坑,是性能变化。
升级之前,我们以为8.4的性能肯定比5.7好。但实际升级之后,发现有些查询反而变慢了。
第一个原因是优化器的变化。MySQL 8.0的优化器有很大的改动,执行计划和5.7不一样。有些查询,在5.7上走的是索引,在8.4上走了全表扫描,性能差了很多。
第二个原因是参数默认值的变化。8.4的很多参数默认值和5.7不一样,比如innodbbufferpoolsize、maxconnections、sortbuffersize等。如果直接用默认参数,可能性能不如调优过的5.7。
第三个原因是新特性的开销。比如,8.4默认开启了一些新特性(比如不可见索引、直方图等),这些特性在某些场景下可能会有额外的开销。
解决方案:
- 用EXPLAIN分析慢查询,调整索引和SQL
- 根据硬件和业务特点,调优MySQL参数
- 对比5.7和8.4的执行计划,找出差异,针对性优化
- 对性能要求高的查询,用SQL Hint强制指定执行计划
我们花了两周时间,做了全面的性能调优,最终8.4的整体性能比5.7提升了20%左右。但这个过程,确实很折腾。
坑五:主从复制和高可用
第五个坑,是主从复制和高可用。
我们的生产环境用的是一主两从的架构,升级的时候,需要先升级从库,再升级主库。但升级过程中,主从复制出了不少问题。
第一个问题是复制格式。5.7用的是statement格式的复制,8.4推荐用row格式。升级的时候,复制格式不一致,导致主从数据不一致。
第二个问题是GTID。8.4的GTID(全局事务ID)和5.7有一些差异,升级的时候,GTID的处理出了问题,导致从库无法同步。
第三个问题是高可用切换。我们用的是MHA做高可用,升级之后,MHA的一些脚本不兼容8.4,切换的时候出了问题。
解决方案:
- 升级前把复制格式改成row,开启GTID
- 按照官方的升级顺序:先升级从库,再升级主库,最后做主从切换
- 升级高可用工具到支持8.4的版本
- 升级后做全面的数据一致性校验
主从复制的问题,差点让我们放弃升级。有一次,从库同步中断了,数据差了几个小时,花了很大力气才恢复。
坑六:第三方工具兼容性
第六个坑,是第三方工具的兼容性。
我们用了很多和MySQL相关的第三方工具:数据备份(xtrabackup)、数据同步(Canal、DataX)、监控(Prometheus + mysqld_exporter)、管理工具(Navicat、DBeaver)、ORM框架(MyBatis、JPA)等。
升级之后,很多工具都出了兼容性问题:
- 旧版的xtrabackup不支持8.4,备份失败
- Canal的旧版本不支持8.4的binlog格式,数据同步中断
- 监控指标有变化,有些监控项失效了
- 旧版的Navicat连接8.4有问题
- MyBatis的一些旧版本,和8.4的驱动不兼容
解决方案:
- 升级所有相关工具到支持8.4的版本
- 对于暂时不支持的工具,找替代方案
- 全面测试所有工具的功能,确保正常工作
第三方工具的兼容性,是最容易被忽略的,但也是最影响升级进度的。我们因为工具不兼容,推迟了一周的升级时间。
差点放弃的时刻
升级过程中,有好几次差点放弃。
第一次是在测试环境升级的时候,数据乱码了,几张核心表的数据打不开。那时候觉得,这个升级太麻烦了,不如继续用5.7,反正还能跑。
第二次是在性能测试的时候,发现核心查询的性能比5.7差了30%,优化了几天都没改善。那时候觉得,8.4也没那么好,不如等更成熟的版本。
第三次是在预发布环境升级的时候,主从复制出了问题,数据不一致,回滚又花了很长时间。那时候觉得,这个升级风险太大了,万一生产环境出问题,责任担不起。
但最后,我们还是坚持下来了。因为5.7已经EOL了,继续用的风险更大。而且,8.4的新特性和长期支持,确实值得投入。
我们调整了策略,不追求一步到位,而是分阶段升级:先升级测试环境,跑稳定了再升级预发布环境,最后升级生产环境。每个阶段都留足够的时间测试和优化,不赶进度。
升级后的体验
最终,生产环境成功升级到了MySQL 8.4 LTS。用了一段时间之后,说说体验。
第一,性能确实更好了。经过调优之后,整体性能比5.7提升了20%左右,特别是复杂查询和大数据量的查询,提升更明显。
第二,新特性很好用。窗口函数、CTE、JSON函数这些特性,让一些复杂的SQL写起来简单多了。以前需要用应用代码处理的逻辑,现在用SQL就能搞定。
第三,稳定性不错。8.4 LTS运行了几个月,没有出现过严重的bug或者崩溃,稳定性和5.7一样好。
第四,安全更强。8.4的安全特性更多,比如更强的密码策略、更细粒度的权限、更好的审计功能。对于企业用户来说,这些很重要。
第五,长期支持省心。8.4 LTS支持到2032年,未来八年不用再考虑大版本升级了,这一点很吸引人。
总的来说,升级到8.4 LTS是值得的。虽然过程很折腾,但升级之后的体验确实更好。
给准备升级的人的建议
如果你也在考虑从5.7升级到8.4 LTS,我有几个建议。
第一,提前做足准备。不要觉得升级很简单,提前读官方文档,列出所有不兼容的变更,评估应用的兼容性,准备测试环境和回滚方案。准备越充分,升级越顺利。
第二,不要跳版本测试。如果条件允许,可以先升级到8.0,跑稳定了再升级到8.4。虽然8.4是LTS,但8.0更成熟,工具兼容性更好。当然,如果直接上8.4也可以,但要做好踩坑的准备。
第三,分阶段升级。不要一上来就升级生产环境,先在测试环境升级,跑稳定了再升级预发布环境,最后升级生产环境。每个阶段都留足够的时间测试。
第四,关注性能。升级后一定要做性能测试,对比5.7和8.4的性能差异。有些查询可能会变慢,需要针对性优化。不要假设8.4一定比5.7快。
第五,检查所有第三方工具。升级前,确认所有和MySQL相关的工具都支持8.4。不支持的,提前升级或者找替代方案。
第六,做好回滚准备。万一升级失败,要有快速回滚的方案。升级前做全量备份,确保能恢复到升级前的状态。
第七,给团队培训。8.4有很多新特性和变化,要给开发和运维团队做培训,让大家了解新特性,避免写出不兼容的代码。
写在最后
MySQL 8.4 LTS的升级,是我们团队今年做的最折腾的一件事,但也是最有价值的一件事。
从最开始的信心满满,到中间的各种踩坑,再到最后的成功上线,这个过程让我们对MySQL有了更深的理解,也让团队的技术能力得到了提升。
"从入门到放弃",是一句玩笑话。实际上,我们没有放弃,而是坚持下来了。因为我们知道,技术升级是必须做的事情,早做比晚做好。
如果你也在做数据库升级,或者在做其他技术升级,希望我的经历能给你一些参考。升级的过程可能很痛苦,但只要坚持下来,结果一定是值得的。
最后,愿所有的技术升级,都能顺利完成,少踩坑,多收获。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录