不停机更换数据库解决方案
随系统规模逐渐增长,总会遇到更换数据库问题。
- 对MySQL分库分表后,需要从原来的单实例数据库迁移到新的数据库集群
- 系统从传统部署方式向云上迁移的时候,也需要从自建的数据库迁移到云数据库
- 一些在线分析类的系统,MySQL性能不够用的时候,就需要更换成一些专门的分析类数据库,比如说HBase
整个迁移过程,既不能长时间停服,也不能丢数据。如何不停机安全地迁移数据更换数据库。
1 不停机更换数据库
设计迁移方案的时候,要做到,每步都可逆。要保证,每执行一个步骤后,一旦出现问题,能快速地回滚到上一个步骤。以订单库为例子。
先把旧库数据复制到新库。因为旧库还在服务线上业务,所以不断会有订单数据写旧库,不仅要往新库复制数据,还要保证新旧两个库的数据是实时同步。要用一个同步程序,实现新旧两个数据库实时同步。
怎么实现两个异构数据库间的数据实时同步?Binlog实时同步数据。如果源库不是MySQL就麻烦,但也可以参考我们讲过的,复制状态机理论来实现。这一步不需回滚,只增加了一个新库和一个同步程序,对系统的旧库和程序都没有任何改变。即使新上线的同步程序影响到了旧库,只要停掉同步程序。
改造订单服务,业务逻辑部分不变,DAO层改造:
- 支持双写新旧两库,并预留热切换开关,能通过开关控制三种写状态:只写旧库、只写新库和同步双写
- 支持读新、旧两库,预留热切换开关,控制读旧库or新库
上线新版订单服务,订单服务仍只读写旧库,不读写新库。让这新版订单服务稳定运行至少1~2周,期间除验证新版订单服务稳定性,还要验证新、旧两个订单库中的数据是否一致。这个过程中,如果新版订单服务有问题,可以立即下线新版订单服务,回滚到旧版本的订单服务。
稳定段时间后,开启订单服务的双写开关,同时停掉同步程序。这个双写的业务逻辑,一定先写旧库,再写新库,并以写旧库的结果为准。
旧库写成功,新库写失败,返回写成功,但记录日志,后续用这日志验证新库是否还有问题。旧库写失败,直接返回失败,就不写新库。不能让新库影响现有业务可用性和数据准确性。上面这过程若出现问题,可关闭双写,回滚到只读写旧库状态。
切换到双写后,新、旧库数据可能存在不一致:
- 停止同步程序和开启双写,这两个过程很难做无缝衔接
- 双写策略也不保证新旧库强一致,这时候要上线一个对比和补偿程序,对比旧库最近数据变更,然后检查新库中的数据是否一致,若不一致,还要补偿
开启双写后,还要至少稳定运行几周,期间不断检查,确保不能有旧库写成功,新库写失败case。对比程序也没发现新旧两库数据有不一致,这时就可认为,新旧两库数据一直保持同步的。
接下来灰度发布把读请求切到新库。期间若初问题,可再切回旧库。全部读请求都切换到新库后,读写请求就已经都切换到新库,实际的切换已完成。
再稳定一段时间后,停掉对比程序,把订单服务写状态改为只写新库。旧库就可下线。整个迁移过程中,只有这步不可逆。但这步主要操作就是摘掉不再使用的旧库,对在用的新库并没有什么改变,实际出问题的可能性已非常小。
就完成在线更换数据库的全部流程。双写版本的订单服务也就完成了它的历史使命,可以在下一次升级订单服务版本的时候,下线双写功能。
2 实现对比和补偿程序
难度
要对比的是两都在随时变换的数据库中的数据。没有类似复制状态机这样理论上严谨实际操作还很简单的方法。但还是可根据业务数据实际情况,针对实现对比和补偿,经过一段时间,把新旧两个数据库的差异,逐渐收敛一致。
订单这类时效性强数据,较好对比和补偿。因为订单一旦完成几乎不会再变,对比和补偿程序,就可依据订单完成时间,每次只对比这时间窗口内完成的订单。补偿逻辑简单:发现不一致,直接用旧库订单数据覆盖新库订单数据。
切换双写期间,少量不一致订单数据,等订单完成后,会被补偿程序修正。后续只要不是双写时,新库频繁写失败,就可保证两库数据完全一致。
麻烦的是更一般case
如商品信息随时可能变化。若数据上有更新时间,对比程序可利用这更新时间,每次在旧库取一个更新时间窗口内的数据,去新库找相同主键的数据对比,发现数据不一致,还要对比更新时间。若新库数据更新时间晚于旧库数据,可能对比期间数据发生变化,这种情况暂不补偿,放到下个时间窗口继续对比。时间窗口的结束时间,不要选取当前时间,而要比当前时间早点儿,如1min前,避免对比正写入的数据。
若数据连时间戳也没,只能去旧库读取Binlog,获取数据变化,去新库对比和补偿。
这些方法严格推敲都不是百分百严谨,都不能保证在任何情况下,经过对比和补偿后,新库数据和旧库完全一样。但大多数情况下,这些实践方法还是可以有效地收敛新旧两个库的数据差异,酌情采用。
总结
设计在线切换数据库的技术方案,首先要保证安全性,确保每一个步骤一旦失败,都可以快速回滚。此外,还要确保迁移过程中不丢数据,这主要是依靠实时同步程序和对比补偿程序来实现。
切换过程按顺序:
- 上线同步程序,从旧库中复制数据到新库中,并实时保持同步;
- 上线双写订单服务,只读写旧库;
- 开启双写,同时停止同步程序;
- 开启对比和补偿程序,确保新旧数据库数据完全一样;
- 逐步切量读请求到新库上;
- 下线对比补偿程序,关闭双写,读写都切换到新库上;
- 下线旧库和订单服务的双写功能。
相关文章
- ORA-01017: invalid username/password; logon denied Oracle数据库报错解决方案一
- js 洗牌算法_数据库洗牌算法
- MySQL数据库原理学习(三十四)
- 库Oracle:新一代数据库解决方案(oracle今天的数据)
- MySQL Variables ssl_ca 数据库 参数变量解释及正确配置使用
- Oracle数据库:高效且可靠的数据库解决方案(oracle数据库的优点)
- 解析Redis数据库储存大小(redis数据大小)
- SQL Server 数据库容灾技术解决方案(sqlserver容灾)
- Oracle数据库中触发器类型的研究(oracle触发器类型)
- Oracle RAC方案:高可用性数据库集群解决方案(oraclerac方案)
- MongoDB SaaS:新一代数据库解决方案(mongodbsaas)
- 达梦数据库:MySQL实现国内领先(达梦数据库mysql)
- 京东数据库技术:基于SQL Server的实践实例(京东 sqlserver)
- 怎样的数据库SQL Server:多功能的数据库解决方案(sqlserver是一个)
- Oracle数据库中快速导入CSV文件的方法(oracle 导入csv)
- MySQL数据库路径修改:一步步操作指南(mysql数据库路径修改)
- MSSQL数据库能否实现数据回滚?(mssql 能数据回滚吗)
- 妙用MySQL数据库:用图片存放记忆(图片存入mysql数据库)
- MSSQL语句:将数据导入数据库(mssql语句导进数据库)
- C 语言使用 MySQL 数据库连接池技术解决方案(c 使用mysql链接池)
- Oracle公共类构建连接简单实用的数据库解决方案(oracle公共类)
- Oracle数据库实现快速配置C语言配置文件方案(c oracle配置文件)
- C语言操作Oracle数据库之旅(c oracle 访问)
- C与Oracle数据库备份安全可靠解决方案(c# oracle 备份)
- 01658oracle解决数据库运行问题的完美解决方案(01658oracle)
- Redis数据库付出了什么样的费用(一个redis的费用)
- 解决方案MySQL数据库不支持TOP命令的替代方法(mysql 不支持top)
- 编码Oracle数据库报错04091解决方案寻求(oracle中04091)
- 学习Oracle数据库,学无止境(oracle xuexi)