一次支付系统升级过程的经验教训

先简单介绍下升级背景:
公司要上线支付系统V3.0,主要增加复式账系统。
新老版本不兼容。即一笔支付交易必须完整走老系统记账或者走新系统记账。
数据库的主要影响是在已有的核心表(3kw)增加若干字段。数据库全部使用MySQL InnoDB引擎。

升级过程:
凌晨2点到7点,5个小时的上线过程中,经历了无法完全屏蔽流量、数据库导入主键冲突、上线步骤遗漏、隔离的UAT环境和配置更新复杂、MySQL5.5和5.6不兼容等问题。

下面按时间发生顺序介绍整个上线过程。

D-2日
RD、QA决定上线,RD开始评审上线CheckList,我们称为CheckList A。
大家一致认为直接在核心表增加字段风险较大,因为表非常大,而且生产机器数据库磁盘不是SSD。

MySQL5.5 即使是pt-online-schema-change也非常难用,已经有过教训。不停服务升级无法完成kw级大表的schema变更。
pt的主要问题在于pt太慢了,整个过程会建很多的触发器,相当于SELECT出来再INSERT进去。另外一个问题是,业务数据库访问比较频繁,抢锁比较严重,pt抢不到锁反而会加重负担,也影响整个改表体验。
其实MySQL5.6官方已经提供了Online DDL的解决方案,除个别情况外,原生的Online DDL都是最优的选择。参考链接:http://seanlook.com/2016/05/24/mysql-online-ddl-concept/index.html
但是我们当时的生产环境数据库还是MySQL 5.5,所以还是用不了

建议方案:
重新部署一套数据库(磁盘使用SSD),在新数据库上线建好更改后的schema,然后暂停线上流量,将全库数据用mysqldump出来,再load到新数据库中。
暂停线上流量再导出数据库,是为了保证数据一致性。(目前我们没有读写分离,而且保留只读功能意义不大)
在新库上建好更改后的schema再导入,这样性能瓶颈就是数据库的写入INSERT。而不是数据库的ALTER。实测在kw级MySQL表上效率更高。

对于业务功能验证,希望完全暂停线上流量后,部署一个隔离的UAT环境,使用真实数据,供QA进行线上验证。

D-1日
按既定方案,SYS和RD进行了完整的预演,主要是数据库操作。
由于涉及模块多,上线步骤复杂,SYS对RD的上线CheckList从方便操作的角度进行了优化,生成了CheckList B。

数据库建议方案从实践上看是没问题的,但是由于数据库过大,实际耗时需要1个小时左右。
QA利用预演环境(区别于UAT环境的点只在于不是真实数据)进行了业务功能验证,无误。

晚上9点开始,给用户推送支付功能升级的大字报。D日凌晨2点到5点停服维护。

D日
凌晨,某会议室,RD负责人,QA负责人,SYS。
0点~1点半。SYS 进行了第二遍预演。过程遇到了数据库导入主键冲突问题,但是重试后解决。

凌晨2点,SYS开始按操作步骤摘流量,屏蔽生产环境流量。但是发现按步骤都操作完了,数据库仍然有新的连接进来,即使强制杀了数据库连接,还有新的。完全不符合预期。(后来发现是一些年久失修的离线作业)

为确保数据一致性,祭出大杀器:FLUSH TABLES WITH READ LOCK
见到数据库连接写阻塞的就kill

新的数据库已经准备好,新的schema也更新好了。现在开始做数据库导入,执行了半个小时,挂了。导入主键冲突!可是怎么可能会有主键冲突呢?
排查了一遍,怀疑是预演过程中,有QA的程序一直在跑自动化Case导致的。断掉QA的连接,重新执行数据库导入,导入成功。

等数据库执行完,已经是4点了。
SYS配置了UAT的APP接入域名,QA开始打APP包进行验证。
包打好了,但是安装后直接crash,无法打开。
经排查,是因为QA配置Jenkins任务时参数填写错误导致。重新打包后,APP打开正常。

APP ready了,后台服务上完线了,开始进行业务功能验证。此时是凌晨4点半。

尽管在预演过程中,业务验证非常顺利,但是在生产过程中,业务验证非常不顺利。基本上每个场景都走不通。那么这只有一种解释,环境配置有问题。
RD负责人开始逐个排查问题,由于涉及到网关、业务入口、支付核心、账务等各个模块,即使有LogTrace辅助进行日志排查,仍然非常耗时。

5点半时,卡到一个关键的场景,业务验证不通过。
QA负责人从风险的角度开始打断RD,想要回滚。这时RD负责人压力非常大,觉得验证不顺利和代码没有关系,都是环境配置问题,涉及模块配置太多,很快就能解决。
连续三次打断后,RD负责人不得不停下来交涉,“到早上7点,有任何责任我背”。(后来了解到QA负责人已经通过别的途径把情况上报给了领导,这是别的话题,撇开不表)

这个过程中,牵涉最多的其实是环境和配置。
诸如:由于CheckListA 和CheckListB不等价,有一些上线步骤被遗留;UAT环境如何管理,新部署的MySQL5.6 mysql.ini和MySQL5.5不一致导致代码不兼容。

6点半的时候主流程都已经没有问题了。
7点正式对外切流量。

后续:
公司对这个项目Review了三遍,从各个角度,项目的角度,开发测试过程,上线过程等。
结论:
1、凌晨上线未必是好的选择。
虽然凌晨是业务流量低峰,但也是人大脑活动的低峰,难以保持兴奋。

2、做好充分的停服预告。
整个上线过程,太过仓促,停服时间超过预期,也没有充分评估用户影响。
停服并不说明方案的设计不好,停服并不是什么丢脸的事情。

3、做好止损红线。
各方提前沟通明确方案和时间点,什么时候冲,什么时候停。
将在外君命有所不受。事先没有约定的约束,在方案执行中不能提,只会增加扯皮的谈资,没有意义。(会上可以随意发表意见,一旦会议打成一致意见,会议纪要一发,就不要再提意见了)

你可能感兴趣的:(一次支付系统升级过程的经验教训)