MySQL存储过程中包含HINT导致升级失败纪实

* GreatSQL使

上午10:00,某运营商核心报表平台升级前夕。

作为万里数据库的战略合作伙伴,某运营商一直密切关注着国产数据库的发展。其系统中一套基于MySQL8.0.11版本的核心报表平台,近期由于存在安全扫描的漏洞,需要尽快将其升级到MySQL8.0.25及以上版本。

由于客户对MySQL新版本存在一定的观望心理,以及对业务验证的充分性待提升,客户最终选择升级到MySQL8.0.25。该运营商客户运维人员按照MySQL官网的流程,提前编写了数据库版本升级方案,并在公司内的测试环境进行了多次验证,然后信心满满地开始评审。

看似一切轻车熟路。该运营商客户的运维组、业务线、项目部等诸多部门在确认了升级方法、changes in MySQL 8.0.25后,评审流程成功通过。接下来,他们根据升级方案在测试环境中进行验证,也没遇到任何阻碍。

在一片安静祥和中,开始提单升级生产环境,直到晚上22:40,万里数据库DBA收到客户的紧急求助,“核心报表平台升级MySQL8.0.11到MySQL8.0.25失败了,运维人员尝试回退但是无法回退成功!!!”。

客户在遇到困难时,第一时间想到了万里数据库。接到客户求助电话后,手握《深入理解MySQL主从原理》、睡眼惺忪的我(DBA运维人员)顿时清醒,以迅雷不及掩耳之势迅速打开电脑,远程登陆客户环境查看情况。

10分钟后,我确定了问题状况:该方案在同版本的测试环境多次验证均成功,当前即使加上选项–upgrade=force也无济于事,确实也无法回退。接着,紧急定位MySQL的错误日志,发现以下信息:初步定位到的地方是,MySQL8.0.11升级到MySQL8.0.25时,涉及data dictionary变更,此时确实无法回滚。由此,升级失败的详细原因需要从更深一层的底层源码分析了,这已经超出了一个普通DBA运维人员的能力范畴!

好在,万里数据库之前是MySQL中国研发中心,公司积累了大量的MySQL源码级资深研发人才。当下办法,只能赶紧联系公司的研发大神。

研发大神经过半小时的gdb调试,锁定到了升级失败的原因:

2022-03-26T22:22:18.224527+08:00 1 [Note] [MY-013627] [InnoDB]     Scanning temp tablespace dir:'./#innodb_temp/'
2022-03-26T22:22:18.234733+08:00 1 [Note] [MY-013018] [InnoDB]     Created 128 and tracked 128 new rollback segment(s) in the temporary     tablespace. 128 are now active.
2022-03-26T22:22:18.235849+08:00 1 [Note] [MY-012976] [InnoDB]     Percona XtraDB (http://www.percona.com) 8.0.25-15 started; log sequence     number 225808521
2022-03-26T22:22:18.254595+08:00 1 [System] [MY-013577] [InnoDB]     InnoDB initialization has ended.
2022-03-26T22:22:18.307905+08:00 1 [System]     [MY-011090] [Server] Data dictionary upgrading from version '80011' to     '80025'.
2022-03-26T22:22:18.308597+08:00 1 [Note] [MY-013327] [Server] MySQL     server upgrading from version '80025' to '80025'.
2022-03-26T22:22:18.533034+08:00 1 [Note] [MY-012357] [InnoDB]     Reading DD tablespace files
2022-03-26T22:22:18.535481+08:00 1 [Note] [MY-012356] [InnoDB]     Scanned 27 tablespaces. Validated 27.
2022-03-26T22:22:19.210608+08:00 0 [ERROR]     [MY-010020] [Server] Data Dictionary initialization failed.
2022-03-26T22:22:19.217762+08:00 0 [ERROR] [MY-010119] [Server]     Aborting
2022-03-26T22:22:19.218695+08:00 0 [Note] [MY-012330] [InnoDB] FTS     optimize thread exiting.
2022-03-26T22:22:19.548897+08:00 0 [Note] [MY-010120] [Server] Binlog     end
2022-03-26T22:22:19.549458+08:00 0 [Note] [MY-010733] [Server]     Shutting down plugin 'MyISAM'
2022-03-26T22:22:19.549518+08:00 0 [Note] [MY-010733] [Server]     Shutting down plugin 'InnoDB'
2022-03-26T22:22:19.549623+08:00 0 [Note] [MY-013072] [InnoDB]     Starting shutdown..

MySQL8.0.25源码中的data dictionary version变更后,升级流程中会检查并编译routines。当检查到含有“Optimizer hint syntax errornear ‘parallel(t1,4)*/”的routine抛出warnings,而MySQL源码把这个warning当作ERROR处理了,引发升级失败。

听到研发大神的答复,心里终于有底了!失败的原因搞清之后,公司的研发大神紧急帮我编译版本包。终于在研发紧急修复、CI构建、用例执行成功后,客户的MySQL版本现场升级成功!

凌晨4:40,进行复现。

升级成功后,此时业务已经影响几小时了,联系运营商客户进行了业务测试,最终成功。但此时的我已经毫无困意,干脆再请教一下研发大神,MySQL bug的复现方法和后续操作。

按照研发大神的指导,在低版本(如MySQL8.0.11)升级到高版本(如MySQL8.0.25)时,只要涉及到dd_version变更,确实会在含warning的routine中显示升级失败(构建warning的routine很容易,参考bug107384复现步骤)。

本着开源共享和回馈MySQL社区的原则,我赶紧将bug提交到MySQL官方。当前,该bug已经验证通过。

bug链接如下:https://bugs.mysql.com/bug.php?id=107384

本次升级的复盘总结和效果反馈

此次的升级过程可谓一波三折,并且也发现了升级流程和方案中很多值得优化的地方。同时,通过帮助客户进行紧急的版本升级和向公司研发大神请教相关的经验和实操方法,我们总结了一些升级反馈和复盘经验,如下:

1.本次升级失败的原因:

  • 属于MySQL代码层面的bug,简要介绍如下:在MySQL版本升级涉及dd_version变更,涉及到routine的hint解析报错(Optimizer hint syntaxerror near ‘parallel(t1,4)*/)时,升级就会失败;
  • 复现方法:MySQL8.0早期版本搭建实例,创建routine(内含hint parser失败的语句),此时升级到新版本(dd_version变更)就会出现。

2.无法回退的原因

MySQL升级跨较大版本,一般指的是dd表变更,升级成功后MySQL的机制就禁止回退。

3.本次的经验教训

  • A.必须在测试环境验证,本次也在同样版本的测试环境验证,但是由于没有涉及routine的hint解析报错场景,所以没验出来;
  • B.测试环境选择上,最好可以充分模拟待升级的环境(表结构、对象、数据量等),充分利用测试环境;
  • C.针对测试环境验证成功的升级方案,也需要再验证下回退流程,提前预知风险。

尽管路途曲折,但此次的紧急响应协助让客户看到了万里数据库的DBA运维人员连夜处理问题的响应时效、处理Bug认真负责的服务态度,以及后台研发人员分析修复问题的能力。在对bug修复和方案的讨论验证过程中,万里数据库和客户的革命友谊也得到了进一步的增进。

此次的升级经验和结果,也为万里数据库后期的客户技术支持工作带来了更多的经验借鉴和信心。未来,万里数据库将一如既往秉持着认真严谨的态度,对待每一次的系统升级、故障处理、产品测试。同时,在国产数据库前进的征程上,万里数据库将一往无前地坚持“极致稳定、极致易用、极致性能”的产品理念,打磨锤炼产品,为GreatSQL每一次的完美进阶全力以赴。


数据运维技术 » MySQL存储过程中包含HINT导致升级失败纪实