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

一、主题分享

大家好!我今天讲的不是什么高深的技术或者产品设计,只是前一段时间发生的真实的上线过程。大家就权当我讲一个故事。里面涉及的技术也比较简单,请大家可以不吝赐教~

1.背景

公司要上线支付系统V3.0,主要增加复式账系统。新老版本不兼容。即一笔支付交易必须完整走老系统记账或者走新系统记账。

数据库的主要影响是在已有的核心表(3kw)增加若干字段。数据库全部使用MySQL InnoDB引擎。整个上线的过程非常惨,折腾了一晚上。

2.升级过程

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

3.上线过程

以下按时间发生顺序介绍上线过程。 为了方便叙述,我们假定D日为正式上线日,D-2日是指上线前两天。

3.1 D-2日

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

实测,按我们生产环境的机器配置,一个3kw的表,加一个字段,大概需要20分钟,这次上线涉及4个这个量级的表,这个时间显然不能接受。

MySQL5.5 即使是pt-online-schema-change也非常难用,已经有过教训。不停服务升级无法完成kw级大表的schema变更。

pt的主要问题在于pt太慢了,整个过程会建很多的触发器,相当于SELECT出来再INSERT进去。另外一个问题是,业务数据库访问比较频繁,抢锁比较严重,pt抢不到锁反而会加重负担,也影响整个改表体验。

其实MySQL5.6官方已经提供了Online DDL的解决方案,除个别情况外,原生的Online DDL都是最优的选择。 mysql 5.6 原生OnlineDDL解析,但是我们当时的生产环境数据库还是MySQL 5.5,所以还是用不了。

讨论后的建议方案是

重新部署一套数据库(磁盘使用SSD),在新数据库上线建好更改后的schema,然后暂停线上流量,将全库数据用mysqldump出来,再load到新数据库中。

暂停线上流量再导出数据库,是为了保证数据一致性。(目前我们没有读写分离,而且保留只读功能意义不大)在新库上建好更改后的schema再导入,这样性能瓶颈就是数据库的写入INSERT。而不是数据库的ALTER。实测在kw级MySQL表上效率更高。

解决了数据库加字段的问题,后面就是业务验证的问题。

目前公司还没有完善的UAT环境(User Acceptance Test,可以理解是完全和生产环境一致的环境,即连正式的数据,正式的API,但是不对外发布,一般是内部业务验证的最后一步)。

由于涉及到记账,这次上线比较重要。对于业务功能验证,希望完全暂停线上流量后,部署一个隔离的UAT环境,使用真实数据,供QA进行线上验证。也就是说,我们要针对这次上线手工打造一个UAT环境。(环境的配置是个大坑,也是后面无数问题的缩影)

3.2 D-1日

按既定方案,SYS和RD进行了完整的预演,主要是数据库操作。由于涉及模块多,上线步骤复杂,SYS对RD的上线CheckList从方便操作的角度进行了优化,生成了CheckList B。(注意:这里区别于前面的CheckList A,是SYS又搞了一个上线CheckList。)

数据库建议方案从实践上看是没问题的,但是由于数据库过大,实际耗时需要1个小时左右。4个3kw左右的表,一共加二十多个字段,1小时搞定。

QA利用预演环境(区别于UAT环境的点只在于不是真实数据)进行了业务功能验证,无误。晚上9点开始,给用户推送支付功能升级的大字报。D日凌晨2点到5点停服维护。

3.3 D日

凌晨,某会议室,RD负责人,QA负责人,SYS。

0点~1点半

SYS牵头进行了第二遍预演。过程遇到了数据库导入主键冲突问题,但是重试后解决。当时并没有定位原因,只是感觉很奇怪。

凌晨2点

SYS开始按操作步骤摘流量,屏蔽生产环境流量。但是发现按步骤都操作完了,数据库仍然有新的连接进来,即使强制杀了数据库连接,还有新的。完全不符合预期。(后来发现是一些年久失修的离线作业)为确保数据一致性,祭出大杀器:FLUSH TABLES WITH READ LOCK,见到数据库连接写阻塞的就kill,读链接无所谓。

新的数据库已经准备好,新的schema也更新好了。现在开始做数据库导入,执行了半个小时,挂了。导入主键冲突!可是怎么可能会有主键冲突呢?真是墨菲法则啊。第二遍预演遇到的问题,到正式执行的时候又碰到了!!刚刚从线上库导出来的数据,不应该有主键冲突的啊!

这是整个上线的第一步,当头一棒,就挂了!

凌晨4点

排查了一遍,怀疑是预演过程中,有QA的程序一直在跑自动化Case导致的。断掉QA的连接,重新执行数据库导入,导入成功。等数据库执行完,已经是4点了。(第一步导库,我们就比预期多花了一个小时。)

SYS配置了UAT的APP接入域名,QA开始打APP包进行验证。包打好了,但是安装后直接crash,无法打开。这次倒不是大问题,经排查,是因为QA配置Jenkins任务时参数填写错误导致。重新打包后,APP打开正常。

但是发现每一步都不顺的时候,真正的不顺可能才刚刚开始。

这种通宵上线,其实大家是有压力的,发现每一步都不顺时,每个人心里都开始有一些变化,但是当时又不好沟通。

凌晨4点半

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

尽管在预演过程中,业务验证非常顺利,但是在生产过程中,业务验证非常不顺利。基本上每个场景都走不通。QA做了冒烟测试,每个场景都不通。但是在预演环境时,都没有问题啊!那么这只有一种解释,环境配置有问题。

RD负责人开始逐个排查问题,由于涉及到网关、业务入口、支付核心、账务等各个模块,即使有LogTrace辅助进行日志排查,仍然非常耗时。LogTrace是我们自研的一个系统,可以根据一个logid串联起这个请求贯穿所有模块的上下文。

早上5点半

通了一些场景,又卡到一个关键的场景,业务验证不通过。

QA负责人从风险的角度开始打断RD,想要回滚。这时RD负责人压力非常大,觉得验证不顺利和代码没有关系,都是环境配置问题,涉及模块配置太多,很快就能解决。(这个项目组付出的太多了,连续一个多月的加班,每周单休,期间项目组成员还感冒,牙痛。)RD负责人知道项目回滚意味着什么,所以想坚持不回滚。但是QA Leader不依。

连续三次打断后,RD负责人不得不停下来交(chao)涉(jia),“到早上7点,有任何责任我背”。

这个过程中,牵涉最多的其实是环境和配置。我们有外网的接入网关,内部又有ESB网关,各个模块的调用非常复杂。

问题点如下:

由于CheckListA 和CheckListB不等价;

有一些上线步骤被遗漏

UAT环境如何管理;

新部署的MySQL5.6 mysql.ini和MySQL5.5不一致导致代码不兼容

每一个点,都是一个大坑。都不是什么技术难点,但是会阻碍场景测试。

为什么在验收的时候没问题呢?一到线上就有问题呢?

因为我们想手工造一个UAT环境出来,又要考虑到回滚方案(一旦决定回滚,如何快速的将所有的配置还原)里面涉及大量手工改配置的地方。

本来配置都有配置服务器管理的,因为我们要手工改这些配置,就会造成生产服务器和配置服务器不一致,要人工在黑板上记住都改动了哪些。(这是第二块黑板了。。。)

早上6点半

主流程都已经没有问题了。

早上7点

正式对外切流量。

后续

公司对这个项目Review了三遍,从各个角度,项目的角度,开发测试过程,上线过程等。

结论

凌晨上线未必是好的选择:虽然凌晨是业务流量低峰,但也是人大脑活动的低峰,难以保持兴奋。像中间漏配置;真实进行UAT验证时,接入网关配置没有打开,这种低级别错误就很难解释。特么这么简单怎么可能忘啊!

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

RD 一开始的上线方案评审想不停服,觉得停服好像非常shame。但其实不是,保证账务不出乱子,用户能正常完成业务功能才是最重要的。停服没什么大不了的。

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

虽然最后项目惊险上线成功了,但是风险还是比较大的。如果7点还解决不了,回滚不但是项目组感情上接受不了的事情,会影响到公司正常业务,才是更大的问题!

分享嘉宾非常详细地描述了上线过程中碰到的各个问题,最后给出一些忠告。 对支付研发而言,每一个坑都要用资金去填平的。仁者见仁,欢迎大家留下您的建议。

二、 Q&A

Q1、这么重要的上线没有事先预演一次呀?

A1、没用的,毕竟环境不一样!而且UAT环境还都是现搭建起来的。

A2、在第二次出问题时就应该中止了!一般都会有同样的模拟环境。

A3、有预演过,预演的问题在于,预演环境的配置和真实生产环境不一致。

Q2、新老数据是否可以双写?

A1、双写的问题,不要做一致性校验啊,考虑过双写的方案。

A2、这样的方案有没有考虑过:存量数据迁移到新库 增量数据在一段时间内同步到老库,待验证没有问题后据情况下掉老库,避免双写,否则一旦出问题都不知道那个数据是正确的了。双写方案一般DB也是不建议做的。我们这边有几个方案,不过一般都是DB支持。

Q2-1、增加数据同步到老库上,这个一般怎么做?因为新老流程的记账模式都不一样。主要感觉这次上线时,最大的点在于,新老版本流程不兼容。又要保证数据强一致,很难有兼容的方案。

A1、比如通过binLOG将增量数据同步到新库。当然这里边是有一套基于binLOG的数据同步机制的。有生产端和消费端。生产端就是新库,消费端就是老库,不需要应用处理。DB层直接搞定。

Q3、这个和主从同步有什么区别?解析binlog?

A1、是的!

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180103B029BZ00?refer=cp_1026

相关快讯

扫码关注云+社区