一、如何看待MySQL版本升级
关于数据库版本升级,一直都是热议话题,对于升级的缘由各家也有所不同,有业务驱动的,有DBA自发驱动的,有规划导向也有方向指引的……抛开各种原因,当升级这个决定落下来的时候,对于DBA手头的几百几千套数据库来说,就好比是一场动物大迁徙,满满的画面感。
从Oracle发布的版本生命周期规划可以看到,MySQL5.7已经走到了生命周期的终点,意味着后续将不再为 MySQL 5.7 提供官方更新、错误修复或安全补丁。
图片
阿里云和AWS都在官方公布了版本支持计划,MySQL 5.7版本已经开始了倒计时。
图片
而要想让这件事情获得研发同学的大力支持,就需要平滑升级或者最低成本的改动。所以对于这场迁移的基本要求,我在心里默默对自己提了要求:零故障,平滑升级。
(一)行业内的MySQL版本数据情况
我在2022年底左右调研了下行业内的一些公司的MySQL数据库版本情况,列表如下:
图片
可以看到大部分的公司还是在MySQL 5.7这个版本,而且从服务规模来看,越是规模大的公司,要想做整体升级这个事情的复杂度就会高出几个数量级。
(二)我们做数据库版本升级的理由
我们做这件事情是从规划导向来切入的,也有一部分DBA自驱的因素。说是规划导向,转义过来就是不打无准备之仗,MySQL后续的整体架构是构建在基础存储之上的,如果基础存储存在瓶颈,对于后续的架构演进也存在明显短板,所以我们在2019年底就开始调研并小范围在新业务中试点MySQL 8.0了。
如下是早期调研中对于MySQL 8.0和MySQL 5.7使用sysbench压测的一些信息供参考,可以看到MySQL 8.0是有明显性能提升的。至于MySQL 8.0的版本,我们的考虑是和验证测试的8.0.19保持一致,在后期支持新版本的无缝升级。
图片
从功能上来说,开发特性更加丰富,SQL优化效果和运维功能上都有明显的提升,在兼容性方面会更加严格(兼容性严格具有两面性)。
图片
在经过了一个相对稳定的周期验证之后,无论从稳定性、性能和功能方面确实达到了预期的效果,有一些特性确实解决了当时的一些运维问题。
说是DBA自驱的理由,是因为我们盘点了一下近些年来的MySQL技术栈使用情况,发现实际的情况比我们预想的要差一些,比如MySQL 5.5我会定义为一个分支技术栈,以此类推,我们目前存在7个分支技术栈。
图片
在这些因素的基础之上,我们以点带面展开分析,发现多分支技术栈散乱只是表象,还有一些潜在问题和瓶颈问题:
1、MySQL版本过旧,架构管理不一致,运维复杂度较高
1) MySQL 5.5和5.6为过旧技术栈,官方已不再维护
2) 未来3年内需要从MySQL 5.7升级至8.0,演进复杂度高
3) 40%操作系统版本过旧,后续的数据库版本升级存在风险
2、部分技术栈已闭源,服务异常时存在恢复风险
1) Infobright已转为商业版维护
2) TokuDB已于2020年不再维护
3、数据库规范和审核机制难以支撑现有的业务需求
1) SQL审核工具解决了早期的研发规范问题,后续闭源难以持续
2) 数据库开发规范已4年未更新,部分开发规范已难以满足业务需要
4、人员稳定性和持续发展
1)DBA不可避免地在做一些重复劳动,一些繁琐的差异化操作势必会削弱工作热情,也会发生一些意料之外的异常
2)个人运维经验无法有效的沉淀转化
所以这是一个综合的问题,涉及到对技术、业务和人的管理,而且是环环相扣。
当然对于一件事情的基本逻辑越简单,实现起来也更聚焦。所以我们进一步提炼了一下目标,7->2,即7个分支技术栈整合为2个,在这个基础上进行生态技术栈的补充和完善。
(三)数据库版本升级的意义
做这件事情有什么好处呢,也就是所谓的意义,我觉得是:降本增效,提高整体业务稳定性。主要体现在如下六个方面:
- 应对未来3年内的数据库基础服务风险,对后续的数据存储平台架构迭代奠定基础(这个需要由明确的规划支撑)
- 通过版本升级提高整体业务性能和稳定性
- 实现支持系统的一致性,提高基础服务支撑能力
- 将单点业务迁移至MySQL主流技术栈,预防故障风险
- 对开发规范和SQL审核机制进行规范化支持和落地
- 为后续的环境标准化建设提供实践经验
我从公有云和私有云的视角盘点了下MySQL技术栈发展的情况,其实MySQL 8.0已经成为了行业主流的基线版本,各种数据库产品层出不穷,如果基线版本已经落后了,后续势必会有整合和返工,所以这也算是一个技术的战略点。在协议兼容的前提下,还需要进一步考虑到国产化数据库的影子,当然也可以有更多的选择,重心在于协议和生态技术栈兼容。
毕竟数据库的升级是一项大工程,大开大合,研发同学再配合支持也需要权衡,所以MySQL 8.0的大版本基础之上,在满足驱动和协议兼容之后,后续的小版本和迭代升级计划都是在8.0的体系之内完全平滑闪断完成,也就不需要研发同学全程跟进了。
(四)数据库版本升级的潜在难点
当然任何事情都得多面看,看到好处(意义),也需要看到难点:
- 跨中心多团队协作,周期较长
- 开发语言技术栈有7个,MySQL 8.0的驱动兼容性都需要充分考虑
- 部分升级改造需要研发侧支持旁路数据双写
- 根据数据库拓扑关联主机业务的亲和性,避免服务器故障
- 按照业务特点和优先级制定差异化升级方案
- 基于滚动模式的数据库资源全量替换,避免资源冗余
- 制定平滑的MySQL集群迁移方案,对业务侵入性最低
因为我们升级的基调是平滑模式,所以基本是资源平替,快速切换的实现策略,在这种情况下,每一个数据库实例都需要反复确认,会有大量的沟通协调工作,况且业务不能停,因为数据库升级直接影响到业务使用,这件事情的性质也就变了。
二、通过五个方面保障数据库升级的稳定性
接下来我会从如下的几个方面来保障整个升级过程的稳定性。
(一)梳理和确认目标和范围
整个数据库版本升级,不是单单有标准版的主从集群,还需要考虑到中间件集群,因为NewSQL集群上线已经完成了兼容性测试,所以不在本次升级的考虑范围之内。
通过这项梳理也能够基本明确其他分支技术栈该如何做方案设计。
图片
(二)制定升级策略
1、整体升级策略
这场数据库版本升级的大迁徙,是从7个分支技术栈收缩为2个,所以需要对不同的分支技术栈规划落地方案,整体上我们是倾向于让MySQL 8.0承载尽可能完整的业务。
图片
因为上一步明确了数据库版本升级的范围是标准版和中间件集群和其他分支技术栈,则需要制定相应的升级策略。
2、标准版升级策略
对于标准版主从来说,如果是MySQL 5.5,5.6版本,需要先过渡到MySQL 5.7,完成兼容性测试之后,观察一段时间之后,再次升级到MySQL 8.0;如果是MySQL 5.7版本,则可以直接升级到MySQL 8.0。
图片
3、中间件集群升级策略
对于中间件集群来说,整体的思路还是做拓扑下沉,即通过级联的方式,把从库提升为主库。
图片
4、其他分支技术栈升级策略
对于其他的分支技术栈来说,这些技术栈早期也确实解决了一些业务厄待解决的问题,随着MySQL 8.0的性能提升和集群技术的迭代,需要做一些整合。
- TokuDB迁移至TiDB
- Infobright迁移至MySQL 8.0
- 对于一些历史遗留业务,还需要研发协助完成数据旁路双写
所以整体来上来看,数据库版本升级不是单一升级到8.0,在策略上需要考虑完整。
(三)定制化升级列表
如果有成百上千个实例要落地升级计划,显然是一件庞大的工程,某个业务有几十个实例,断断续续地沟通,研发同学也受不了,而且整体的进度也不好控制,所以我们是从两个维度来做梳理和整合的。
- 先按照数据库版本把所有业务的信息都梳理出来,比如MySQL 5.6,MySQL 5.7的,可以整理成不同的tab页,按照业务负责人进行汇总;
- 然后按照不同的业务大类或者业务负责人,把上面这个数据中的信息提取出来,这样就形成了业务视角的数据库升级计划,基本就可以开始和研发同学沟通了;
- 当然沟通也不能全靠嘴,还需要一些标准化的文档,比如我们整理了不同版本升级需要注意的事项,把整个过程需要研发协助的事情都列清楚,避免重复的解释和无效沟通;
- 最后是回退方案,这应该是整个方案里面研发同学最关心的部分了,毕竟先把最坏的结果考虑到,一旦发现问题也能及时处理。
如下是我们计划和研发同学进行的沟通的双方协作的流程。
图片
(四)研发驱动兼容性/功能测试
1、数据库驱动兼容性测试
数据库驱动测试是升级的一个关键环节,而且涉及到很多开发语言,所以兼容性测试是重中之重。
为了避免走弯路,我们先期和一些研发同学一起梳理测试,整理了如下的驱动兼容性列表,这样后续的一些研发同学接入时,就可以参考了。
图片
而对于C++、.NET、Python、PHP、Go、NodeJS等开发语言,兼容性变动相对较小,总结如下:
图片
除了驱动型兼容测试,对于MySQL的不同分支版本,也需要进一步测试SQL兼容性和其他注意事项。
2、MySQL 5.5,5.6升级到MySQL 8.0的兼容性测试:
1)针对group by语法、日期格式字段等有特定要求
如对于group by聚合操作,select列必须在group by中出现,若不在group by子句中,认为不合法。示例:
mysql> select name,age from test group by name,age;
+------+------+
| name | age |
+------+------+
| aa | 18 |
+------+------+
1 row in set (0.00 sec)
mysql> select name,age from test group by name;
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.test.age' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
对于group by聚合操作,order by 列必须在group by中出现
mysql> select name,age from test group by name,age order by name;
+------+------+
| name | age |
+------+------+
| aa | 18 |
+------+------+
1 row in set (0.00 sec)
mysql> select name,age from test group by name,age order by id;
ERROR 1055 (42000): Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'test.test.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
mysql>
- 解决方案1:研发侧调整对应的SQL语句
- 解决方案2:调整MySQL5.7/8.0的sql_mode参数,保证兼容MySQL5.5的语法
2)MyISAM存储引擎的表可能存在潜在问题
解决方案:经过排查,目前线上bbs的库表均为innodb存储引擎或者memory存储引擎
3)部分SQL会出现执行计划发生改变,可能需要略微调整
解决方案:目前暂时没有发现,后续有类似SQL,可以针对性处理
4)字符集验证
MySQL5.7默认字符集是utf8字符集,如果是gbk等字符集需要调整并验证
解决方案:DBA侧保证升级过后,不会出现乱码等字符集报错信息
3、MySQL 5.7升级到MySQL8.0的补充兼容性测试:
1)表中需要包含主键
在8.0版本中会强制要求表中包含主键
2)timestamp数据类型默认值
如果表结构中有timestamp类型字段,并且设置了默认值DEFAULT CURRENT_TIMESTAMP,建议将参数设置为off:
explicit_defaults_for_timestamp=OFF(8.0默认为on)
否则有可能会出现:Error:1048 - Column ‘createTime‘ cannot be null
3)执行计划变化
部分SQL会出现执行计划发生改变,可能需要略微调整
解决方案:跨版本升级中的SQL异常,可以通过提前交付只读实例来进行预先验证,并且抓取原库的慢日志在8.0数据库中进行回放验证
4)MySQL8.0 新增关键字(如rank),可能导致查询、写入失败
mysql> select rank from activity_public_log limit 1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'from activity_public_log limit 1' at line 1
解决方案:改写成 `rank`或者调整字段名
mysql> select `rank` from activity_public_log limit 1;
查询方式:
select TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME from information_schema.COLUMNS where COLUMN_NAME="rank";
5)对于load权限的确认
部分业务具有导入数据的权限,在默认模板中参数secure_file_priv和local_infile是关闭的,需要和业务侧确认是否有该类需求,或者从定时任务中识别
6)存储过程权限检查
部分业务中存在存储过程时,对于存储过程的权限粒度 invoker和definer差异可能导致迁移后业务调用失败,需要在迁移中进行检查
(五)制定资源申请和回收流程
有了前面的流程支持,整个过程基本可以跑起来了,还有一个风险则是采用资源平替的方案,也就意味着今天数据库实例是业务A的主库,完成升级之后我们会让系统的同事重新格式化后交付给我们,很可能明天就变成业务B的从库了,所以资源是以资源池的形式在反复利用,对于如何申请资源和下线资源就是关键,我们制定的流程是需要至少3次审核才可以下线,而且下线的过程中还需要有一定的观察期窗口。
为此我们也指定了专人负责制度,即最终的下线操作只能由固定的一个人来操作,他需要对下线操作做最后的审核,并且负责。
三、版本升级问题总结
具体实施的过程还是相对顺利的,为此我们也储备了一些标准化能力,比如平台化搭建跨版本从库的服务,保证每个人交付的质量是基本一致的。
所以结果整体上是预期中的,当然也发现了一些潜在问题,通过梳理和总结,也在其他业务方向能够参考借鉴,提高了整体服务升级的稳定性和专业性。
图片
版本升级的事情做完了,也盘点出了一些新的收获:
(一)业务便于接入:通过大规模升级的过程对于多语言体系的兼容性支持做到了心中有数;
(二)数据库子版本平滑升级:后续的子版本升级演变为在线升级模式,就不需要研发做额外的沟通和测试;
(三)操作系统无感升级:操作系统升级可以演变为平滑升级模式,CentOS 7后续的版本选型和支持都可以做一些调研测试;
(四)资源治理:通过升级也发现有一些服务资源使用率不足需要降配,后续可以开展容量治理。
四、小结
MySQL版本升级工作,从2022年上旬开始规划到生态完善实施了近1年,得到了多个中心研发团队的大力支持和理解。MySQL数据库也从原本的7个技术栈收缩为2个,挑战和难度在落地时才发现比预期的要复杂不少,为了保证业务的稳定性和研发工作的侵入度最低,DBA团队也制定了完整的数据升级流程和业务切换方案,并对业务异常的回退进行了全流程准备,整个过程零故障。
后续计划在SQL云数据库、SQL高可用体系,SQL分布式架构体系和SQL资源标准化四个方面持续发展,并制定相应的建设计划。
(一)SQL资源标准化:MySQL 8.0作为基线版本,为后续的运维管理工作提供统一、标准的基础服务支持,并对外提供一致性系统服务,后续提供平滑升级的平台化方案;同时做一些资源治理,对一些使用率不足的业务可以在线降配。
(二)SQL分布式架构体系演进:随着水平扩展需求、信创、分布式事务方案的调研和业务落地演进,未来可能会基于OceanBase等国产化数据库进行对比分析,适时引入;
(三)SQL高可用体系:SQL高可用体系对于标准版主从集群会基于MySQL 8.0版本作为基线,对于拓扑发现,数据管理模式会基于新的运维命令和使用模式;
(四)SQL云数据库服务支持:基于MySQL 8.0的服务体系会在功能和性能上面提供更加丰富,高性能的数据存储支持,如对于JSON的格式解析和查询等,对于SQL查询优化的优化器支持等。
作者介绍
杨建荣,竞技世界数据库专家、dbaplus社群联合发起人,腾讯云TVP,Oracle ACE,《Oracle DBA工作笔记》和《MySQL DBA工作笔记》作者;现就职于竞技世界,擅长数据管理、数据迁移、性能优化,目前专注于开源技术、运维自动化和性能优化,坚持写技术博客,已坚持2400多天。