15|数据迁移:如何在不停机的情况下保证迁移数据的一致性?
数据备份工具
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了在不停机的情况下如何保证数据迁移的一致性,并介绍了MySQL上常用的数据备份工具、innodb_autoinc_lock_mode参数对主键生成策略的影响、面试准备建议以及全面的不停机数据迁移方案。文章还重点讨论了初始化目标表数据和第一次校验与修复的具体操作。此外,还提到了利用binlog进行触发校验和修复的方案,以及切换双写顺序和保持增量校验和修复的重要性。整体而言,本文内容涵盖了数据迁移的技术细节和面试准备建议,对读者快速了解数据迁移的一致性保证具有指导意义。文章内容丰富,涵盖了技术细节和实用建议,适合需要深入了解数据迁移技术的读者阅读。
《后端工程师的高阶面经》,新⼈⾸单¥59
全部留言(22)
- 最新
- 精选
- Johar1.由于目标表没有数据需要全量同步源表数据,会占用源库的资源,可能影响性能,此外,在进行检验恢复数据时,需要切换目标表为主库,才能写目标表。 2.可以,但是不好确认目标库数据是否已经入库,同时插入可能存在冲突,考虑这种情况,可以使用消息总线的延时队列,另外在双写目标库时使用insert into ignore进行写入。
作者回复: 赞! 而且第二个问题还要考虑数据覆盖的问题,所以不怎么适合。
2023-07-20归属地:重庆3 - peter请教老师几个问题: Q1:导出源表时,截止点怎么定?数据一直在写入,在哪一行停止导出? Q2:假设表中有一百万行数据,导出到目的表后,需要校验数据的正确性吗? 怎么校验?逐行对比,而且每一行都对比每一列吗? Q3:标记位是业务代码中设置的吗?还是MySQL中设置的? Q4:Insert语句怎么拿到主键?Insert执行后返回0或1,表示插入是否成功,也没有返回主键啊。 Q5:切换双写部分的第一个图,没有目标表,可能是个笔误。
作者回复: 1. 你不需要关心截止点。你只需要在导入数据之后,找到每张表对应的最后更新时间,就可以认为是那个截止点。 2. 严格做法就是逐行比对。有些公司会抽样比对,但是抽样比对我个人认为效果很差。比如说你一千万行数据,出错几率是万分之一,你抽样是百分之一,你发现错误的几率,也就是百分之一。就是执行时间会很长,我们之前逐行比对,有执行过好几天。 3. 业务代码管理,MySQL 没有感知。 4. 你可以拿到 last insert id。这是 mysql 协议规定的。但是你用的 ORM 框架可能屏蔽了,所以你需要找找。 5. 感谢提醒,我们修复一下。
2023-07-19归属地:北京2 - sheep回答课后问题: 1. 初始化时目标表数据为空,作为源表的一个从库的话,同步过程中会占用源库的资源,影响性能。另外从库一般只提供读功能,此时要实现双写的话,就得把从库readonly=true关闭,另外此时支持从库支持写入后,从库同步应用主库过来的数据往往会有意想不到的问题(比如:主键冲突) 2. 可以,但得考虑的消费SQL时候,可能找不到对应数据了
作者回复: 赞! 1. 要考虑的问题就是很多,主键冲突是一方面,还有就是主键过来一个 UPDATE,而我连初始数据都没有,就更加麻烦了。 2. 嗯,要考虑覆盖数据,以及乱序的问题。
2023-10-24归属地:广东1 - sheep1. “数据一致性问题”这里,"写入源表成功了,但是写入目标表失败了,该怎么办?那么最基础的回答就是不管"。这里一两条的话,确实可以通过后面修复机制去完善。但是这里一直失败的话,也不管么 2. "数据一致性问题"这里,"UPDATE xxx WHERE a = 123"什么情况下目标表会写入失败呢?另外为啥通过消息队列的处理方式没办法定位到源表的哪一行?不就是a = 123这一行么
作者回复: 1. 一直失败就确实得管,这种时候多半是代码有问题,比如说我们之前目标表的列类型变了,导致源表的数据读到程序里面,再存储的时候,就发现数据库类型-Go类型-数据库类型这个转换崩了,只能是打补丁。 2. 因为当你收到消息的时候,原本 a= 123 的可能又被修改为 a = 124 了,所以你找不到。
2023-10-17归属地:广东1 - nadream什么时候停止第一次校验与修复?是在开启双写前吗?那停止第一次校验与修复步骤与开启双写步骤会不会存在时间差,导致这段时间内的数据丢失。
作者回复: 好问题。第一次校验与修复,你随便跑一下就可以,后面还要持续运行增量校验,也可以设置增量校验的起始时间从你第一次校验跑完之后的时间点之后开始进行。 后续要是觉得不保险你就可以运行全量校验或者增量校验。
2024-02-20归属地:浙江 - nadream双写的时候,一个源表可能对应多个目标表,该怎么处理呢?
作者回复: 只能追求最终一致性。也就是说,源表对应多个目标表,如果目标表在不同的数据库上(你没有办法用本地事务),那么就做好监控、告警以及数据校验和修复。实际上,它只是放大了不一致的风险。写单表还是写多表,监控、告警和数据校验与修复都少不了。
2024-01-20归属地:浙江 - nadreamGORM ConnPool 替换这块有详细代码吗?看的不是很明白
作者回复: 我给训练营上课写的一个,你可以参考。https://gitee.com/geektime-geekbang_admin/geektime-basic-go/blob/master/webook/pkg/gormx/connpool/doublewrite.go
2024-01-20归属地:浙江 - Geek_6c2524老师,想请教下,切换写入流程的时间节点是什么时候?比如,双写开始多久之后从——读写源表+写目标表,切换到读写目标表+写源表;多久之后,系统从双写切换到最终的单写到新目标表里?
作者回复: 一般来说,在运行增量校验和修复一段时间之后,发现系统运行很平稳,就可以切换了。实际上这个过程也没想的那么高危,毕竟你可以再切换回来。实在不放心,就挑个半夜凌晨切换。
2024-01-03归属地:上海 - Geek_3d0fe8一下子切换到新系统太粗暴了,我们之前的做法是每个用户都打上状态的标记,决定读写走哪个系统
作者回复: 其实你这就是用户粒度上的控制而已。也就是,每一个用户都可以单独控制,本质上没区别的。 我个人认为,没太大必要。在经过双写以目标表为准的阶段之后,直接切也没问题。 用户维度的控制,对于数据校验来说,很难搞,你得明确知道用源表数据,还是用目标表数据来校验和修复。
2023-12-11归属地:广东 - jCodePorter老师有没有Java版本实现双写的案例参考
作者回复: 以前的工作代码写过,但是开源的没有。 有很多做法: 1. 利用 spring 的 AOP,拦截数据库操作,而后引入双写步骤 2. 利用连接池的扩展机制,把单写变成双写。比如说一般连接池都有类似于 Conn 的抽象,Conn 就会发起真的查询,那么你就可以扩展一个实现。
2023-10-27归属地:河南