数据迁移方案

 一、数据迁移背景

问题场景:

现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?

1.1 停机迁移方案

我先给你说一个最 low 的方案,就是很简单,大家伙儿凌晨 12 点开始运维,网站或者 app 挂个公告,说 0 点到早上 6 点进行运维,无法访问。

接着到 0 点停机,系统停掉,没有流量写入了,此时老的单库单表数据库静止了。然后你之前得写好一个导数的一次性工具,此时直接跑起来,

然后将单库单表的数据哗哗哗读出来,写到分库分表里面去

导数完了之后,就 ok 了,修改系统的数据库连接配置啥的,包括可能代码和 SQL 也许有修改,那你就用最新的代码,然后直接启动连到新的分库分表上去。

验证一下,ok了,完美,大家伸个懒腰,看看看凌晨 4 点钟的北京夜景,打个滴滴回家吧。

但是这个方案比较 low,谁都能干,我们来看看高大上一点的方案。

1.2 双写迁移方案 

简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,除了对老库增删改,都加上对新库的增删改,这就是所谓的双写,同时写俩库,老库和新库

扫描二维码关注公众号,回复: 13418986 查看本文章

然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新库,写的时候要根据 gmt_modified 这类字段判断这条数据最后修改的时间,

除非是读出来的数据在新库里没有,或者是比新库的数据新才会写。简单来说,就是不允许用老数据覆盖新数据

导完一轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次写。

反复循环,直到两个库每个表的数据都完全一致为止。

接着当数据完全一致了,就 ok 了,基于仅仅使用分库分表的最新代码,重新部署一次,不就仅仅基于分库分表在操作了么,还没有几个小时的停机时间,很稳。

所以现在基本玩儿数据迁移之类的,都是这么干的。

二、数据迁移扩展

项目初始,是单库,分了2个表 就可以满足业务数据需求。

随着时间推移,多年后,数据越来越多,当前的数据库设计已经不能满足当前设计。

于是,需要如上图一样,进行分库再分表。

 2.1 同步双写方案

 如上图所示

1. 应用还是保持从旧库中读写数据

2. 编写个应用,通过canal将增量数据通过新的分库分表规则也同时写入新库

3. 同时 编写个旧数据的迁移的工具,通过新的分库分表规则写入新库。

4. 旧数据迁移完成后,验证新旧库中数据是否一致,一致后,既可切换位新库。

三、具体的迁移方案

双写方案,也是一个高可用的平滑迁移方案,这个方案主要分为四个步骤。

数据迁移前,上游业务应用通过旧的服务访问旧的数据

3.1 步骤一

双写,写旧库,同时写新库

服务进行升级,对“旧库上的数据修改”(这里的修改,为数据的insert, delete, update),在新库上进行相同的修改操作,这就是所谓的“双写”

主要修改操作包括:

(1)旧库与新库的同时insert;

(2)旧库与新库的同时delete;

(3)旧库与新库的同时update;

由于新库中此时是没有数据的,所以双写旧库与新库中的affect rows可能不一样,不过这完全不影响业务功能,只要不切库,依然是旧库提供业务服务

这个服务升级风险较小:

(1)写接口是少数接口,改动点较少;

(2)新库的写操作执行成功与否,对业务功能没有任何影响

3.2 步骤二

数据迁移工具

研发一个数据迁移工具,进行数据迁移。这个数据迁移工具,把旧库中的数据转移到新库中来。

这个小工具的风险较小:

1. 整个过程依然是旧库对线上提供服务;

2. 小工具的复杂度较低;

3. 任何时间发现问题,都可以把新库中的数据干掉重来;

4. 可以限速慢慢迁移,技术同学没有时间压力;

数据迁移完成之后,就能够切到新库提供服务了么?

答案是肯定的,因为前置步骤进行了双写,所以理论上数据迁移完之后,新库与旧库的数据应该完全一致。

由于迁移数据的过程中,旧库新库双写操作在同时进行,怎么证明数据迁移完成之后数据就完全一致了呢?

 

如上图所示:

1. 左侧是旧库中的数据,右侧是新库中的数据;

2. 按照primary key从min到max的顺序,分段,限速进行数据的迁移,假设已经迁移到now这个数据段,

数据迁移过程中的修改操作分别讨论:

1. 假设迁移过程中进行了一个双insert操作,旧库新库都插入了数据,数据一致性没有被破坏

2. 假设迁移过程中进行了一个双delete操作,这又分为两种情况

情况一:假设这delete的数据属于[min,now]范围,即已经完成迁移,则旧库新库都删除了数据,数据一致性没有被破坏;

情况二:假设这delete的数据属于[now,max]范围,即未完成迁移,则旧库中删除操作的affect rows为1,新库中删除操作的affect rows为0,

但是数据迁移工具在后续数据迁移中,并不会将这条旧库中被删除的数据迁移到新库中,所以数据一致性仍没有被破坏;

3. 假设迁移过程中进行了一个双update操作,可以认为update操作是一个delete加一个insert操作的复合操作,所以数据仍然是一致的。

除非,在一种非常极限的情况下:

1. 数据迁移工具刚好从旧库中将某一条数据X取出;

2. 在X插入到新库中之前,旧库与新库中刚好对X进行了双delete操作;

3. 数据迁移工具再将X插入到新库中;

这样,会出现新库比旧库多出一条数据X。

但无论如何,为了保证数据的一致性,切库之前,还是需要进行数据校验的

3.3 步骤三

数据校验工具

在数据迁移完成之后,需要使用数据校验的小工具,将旧库和新库中的数据进行比对,完全一致则符合预期,如果出现步骤二中的极限不一致情况,则以旧库中的数据为准

这个小工具的风险依旧很小:

1. 整个过程依然是旧库对线上提供服务;

2. 小工具的复杂度较低;

3. 任何时间发现问题,大不了从步骤二开始重来;

4. 可以限速慢慢比对数据,技术同学没有时间压力;

 3.4 步骤四

切到新库

数据完全一致之后,将流量切到新库,完成平滑数据迁移

至此,升级完毕,整个过程能够持续对线上提供服务,不影响服务的可用性。

3.5 总结

双写方案,四个步骤:

1. 服务进行升级,记录“对旧库上的数据修改”进行新库的双写;

2. 研发一个数据迁移小工具,进行数据迁移;

3. 研发一个数据比对小工具,校验数据一致性;

4. 流量切到新库,完成平滑迁移;

数据迁移方案同步双写方案数据迁移

猜你喜欢

转载自blog.csdn.net/qq_38826019/article/details/121248456