我们在阿里云有一个大的分库分表DRDS数据库,承载着平台的全部业务和数据(这个架构设计不合理),年耗资近百万。
因为5年前就开始使用,这个DRDS数据库版本较老,性能没有新版本好且存在较多的问题(如information_schema表损坏、DTS迁移数据不成功等),所以迫切地需要进行升级。
但这个数据库是整个平台的核心,升级它需要整个平台“停机”。
如何确保升级的成功和保障尽量短的停机时长,是这次升级的要点。
以下是我们这次数据库升级的方案设计、升级过程、及升级后故障的处理记录。
1、升级前测试验证,确保业务不会因数据库版本出现异常;
2、做好升级步骤设计并演练;
3、做好升级失败回退预案。
在测试环境,我们有一个旧版本的DRDS数据库,我们先将它升级到新版本,然后测试验证主要业务流程是否异常。
这里要注意,新版本一定要是我们目标版本,要完全一致。假如目标版本是V1.1,就要升级到V1.1,不要升级到V1.1.1,虽然只相差一个小版本,但在V1.1.1上验证通过,不能证明在V1.1版本就没问题。
1、购买一个新版本库;
2、将旧版本数据库存量数据通过DTS同步到新版本库;
3、建立旧版本库与新版本库实时同步通道,确保数据一致;
4、根据“最短停机时长方案”,提前做好业务应用的数据库切换配置;
5、升级时,主要流量入口负载均衡切换至“平台停机维护页”,告知用户;
6、数据库切换前,将新库表的自增主键增加一个阶梯,确保切换后旧库同步过来的数据和新库中业务应用新生成的记录不会主键冲突;
7、切换数据库配置;
8、主要流量入口负载均衡切回至应用;
9、配置新库到旧库的增量同步通道,为可能的升级失败回退做准备。
1、回退前,主要流量入口负载均衡切换至“平台停机维护页”,告知用户;
2、切换数据库配置。
最后,我们按照上述步骤,在测试环境进行了升级及回退的演练。
所有操作尽量前置,升级时一键完成。
购买新库、ECS、Kafka、Redis等,完全复制一套现有环境,不导入任何流量,旧库与新库通过DTS同步数据;升级时,一键切换业务流量到新环境,实现升级。
优点:
缺点:
购买新库,旧库与新库通过DTS同步数据;提前准备好应用连新库配置文件,升级时重启业务应用。
优点:
缺点:
购买新库,旧库与新库通过DTS同步数据;引入负载均衡组件Nginx,先将应用全部无感重启以通过负载均衡组件接入旧库,准备好新库的负载均衡配置,升级时一键切换;之后再无感重启应用直连新库。
优点:
缺点:
升级过程基本按照“升级步骤”完成。当然,过程中也出现了一些小插曲,主要是:
小插曲们虽然影响不大,但也给我们上了一课:所有操作最好是一步操作就能完成,并且做好提前验证。
升级过程虽然基本顺利,但升级后还是出现了严重的问题,问题就出在“给新库表的自增主键增加一个阶梯”这个步骤上。
出于性能考虑,DRDS数据库的分表会提前申请一部分主键自增值,不能像操作单机版MySQL那样,通过修改AUTO_INCREMNET就能重置主键自增值。
所以我们的部分表主键自增值没有正确重置,业务系统插入数据报主键冲突;同时因为是分库分表的数据库,一部分主键重复的记录插入不同的表时也能成功,导致数据关联错乱,客户看到了不属于他的数据。
升级时熬了一个通宵,升级后又花了一天时间处理主键冲突记录,真是一把辛酸泪。
不过整个过程还是很有收获的,收获如下:
1、“巧用”负载均衡,将数据库升级改成数据库切换,有效缩短停机时长。
2、复杂操作流程,尽量通过操作前置,实现一键操作,并且不易出错。
3、任何一个方案,都要综合考虑它的适用条件并做好验证。这次数据库表自增主键修改,就是没有做好提前分析和验证。