13

跨云迁移过程中的数据一致性实践

 3 years ago
source link: https://zhuanlan.zhihu.com/p/335751536
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

随着互联网业务发展和对容灾的需求,以及对访问加速、多供应商成本控制等要求,互联网公司通过跨云部署和迁移来更好的控制成本逐渐成为刚需,跨云部署和迁移也就成为运维圈子里的一个热门话题,而在此过程中,对运维和研发最头痛就是数据的迁移和分布。

粤语中有一句谚语“ 上屋搬下屋,搬洒一箩谷 ”,意思是在各种各样的搬动过程中,或多或少都会伴随一些资产的流失,这对于互联网业务来说是难以接受的。

通过对最近几次客户的多云部署进行总结,过程中存在的挑战有三点:

首先是数据完整性和一致性挑战。

其次是时效性,迁移窗口期相对有限。

再者是依赖性和各种访问关系。

在大多数实际环境中都存在着应用依赖性,如何万千关系中理顺每条访问关系也是让人望而却步的事情。

跨云迁移涉及到的资源一般可以分成三大类:

第一类是EIP、VPC、负载均衡和NAT网关这类网络服务,在跨云迁移的过程中这些都会发生变化,而且是无状态服务,配置并不复杂,对于这部分资源可以通过人工的方法对齐配置。

接下来是最为常见的云主机资源,这部分我们可以通过USMC服务器迁移工具来进行迁移,对于一些例如zookeeper的服务,也可以通过人手同步配置的方式来迁移。

而第三类就是包括数据库、文件存储和对象存储在内的一些存储服务,我们可以通过UDTS等工具进行迁移,而这正是本文所重点讨论的实践内容。

e2AVBrr.jpg!mobile 跨云迁移

在这些客户的多云部署和迁移过程中,如何在有限的业务暂停时间里,将大量数据进行迁移,并且保证数据一致,有了较多实践和沉淀。为给大家提供有效的借鉴意义,花了一些时间从实践总结了共性,将跨云迁移划分为三个阶段: 数据同步阶段、数据规整阶段(清理测试产生脏数据)和数据割接阶段 进行阐述。

1. 数据同步阶段

数据同步阶段主要是需要解决两个问题,其中最主要的还是跨云迁移的核心,即将数据复制到新平台,并且让应用程序在新平台运行,其次就是利用真实数据对应用程序进行测试,确认应用程序在目标平台可以符合预期地运行。我们都知道数据可以分为结构化数据和非结构化数据,用来存储数据的方法众多,无法逐个深入分析,所以笔者在这里只提供一些最常见的存储组件的迁移实践,其它不同的存储组件各有不同,但也是可以参考这几个组件的迁移逻辑来处理的。

下面将分别讨论 MySQL、文件存储和对象存储 的数据同步方式。

1.1 MySQL同步

一般来说,我们认为对于MySQL的同步,只要存量数据和增量数据都能做到一致,那么整个数据库的同步就是一致的。

而常见的MySQL数据迁移方式有两种:一种是基于MySQL主从的方式,通过mysqldump记录下binlog位置,然后把这个binlog位置前的数据完整导出,恢复出一个备库,然后再从记录的binlog位置开始向主库追平增量数据。另一种就是UDTS工具,但总体上也是分为存量阶段和增量阶段,增量阶段的追及是将从存量同步发起的一瞬间开始往后的数据变化通过binlog的形式同步到目标库。

增量同步依靠binlog完成,这是MySQL主从同步的基础,是我们需要默认信任的数据一致性机制,所以反过来说,如果我们不信任MySQL的binlog机制,那么其它MySQL的数据一致性机制也是需要怀疑的,包括数据落地的fsycn()调用是否真正的把数据写入到磁盘和事务等等,这样就陷入了怀疑论了。当然我们最终需要以数据校验结果来确认数据是否一致。

简而言之, 跨云迁移过程中MySQL的数据一致性主要就集中在存量数据的迁移如何保证一致。

【案例】

以近期的xx公司迁移到UCloud为例,其涉及数据库实例有数十个,并且由于应用依赖的原因需要进行整体迁移。在这案例中,如果采用mysqldump的方法,那么这数十个数据库都需要经过导出、传输、导入和配置主从这样的操作,给整个迁移任务增加了不少工作量。同时也正如很多商业智能应用需要将数据汇总用作分析,他们业务系统也有类似的汇总数据库,这种级联关系会让数据同步操作进一步复杂化。最终客户使用了UDTS作为跨云数据同步的解决办法,在保障数据一致的同时,DBA只需要提供两边数据库的连接和账号信息即可将数据同步任务托管,释放了精力去处理业务上的数据库工作需求。

1.1.1 数据同步

前面提到MySQL事务,在理解存量数据迁移过程中的数据一致性时,需要先了解InnoDB为代表的事务引擎和MyISAM代表的非事务引擎。使用MyISAM引擎的数据表确实没有很好的数据一致性确保手段,存量数据只能对数据表加读锁并迁移,在完成存量数据同步后,通过binlog追平,这样因为读锁会阻塞数据的写入,会导致业务的写入功能不可用,而且这一不可用的时间视表中数据体量而定。

幸而因为MyISAM的不灵活,实际互联网公司中已经很少使用MyISAM引擎了。而InnoDB引擎因为它支持事务和行级锁的特性,在数据同步过程中对业务的影响小很多,但也因此对数据一致性的保护方法也相对复杂,而这一套一致性保护方法,核心就在于基于连接session的事务隔离和基于MVCC的数据版本管理。

在存量数据同步启动的时候,数据迁移工具会在自己对数据库的连接session上设置事务隔离级别为REPEATABLE READ,自动提交设置关闭,并且启动一个事务。这个时候,只要这个session上的这个事务最终没有隐式或显式的提交,这个session里看到的数据就不再发生变化,这样就可以保证存量阶段的数据都是同步任务启动那个瞬间的数据,而不管其它session连接会对数据库做怎么的修改。之所以能做到这样,是因为使用了InnoDB引擎的表有三个隐藏列,分别是行ID DB_ROW_ID,行事务ID DB_TRX_ID和回滚指针DB_ROLL_PTR,同时在相同表空间内维护undo log。

对于insert操作,会在表空间内写入一行数据,记录DB_ROW_ID 和DB_TRX_ID,但DB_ROLL_PTR为null;对于update操作,则undo log是写入一行数据并且根据update语句更新字段数值,记录DB_ROW_ID 和DB_TRX_ID,同时DB_ROLL_PTR指向被修改前的数据行;至于delete操作,则复制数据到undo log中,记录数据删除位,并且将DB_ROLL_PTR指向原先数据。假设数据导出事务启动的同时,mysql上面还有多个活跃事务,这时候数据导出事务就是存量事务中DB_TRX_ID最新的一个,记为Tmax,而这些事务中最老的事务ID为Tmin,而从表空间中导出的每一行的数据为T,通过这些事务ID和一定的比较方法,就可以判断读出的数据对于数据导出任务是否应该保留。

如果T比Tmin还小,或者T小于Tmax且不属于数据导出事务启动时的任何活跃事务,说明这一行数据在数据导出前已经落地,如果还没有被删除则应该予以保留,而其他行则通过DB_ROLL_PTR从undo log中找到数据的上一版本,再通过上一版本的DB_TRX_ID再进行迭代判断。这一处理过程,就是InnoDB引擎的MVCC版本控制实现。

RNNJRza.jpg!mobile InnoDB的undo log和MVCC实现

1.1.2 数据校验

数据一致性的关键,除了数据同步过程中的一致性保障,更加简单直接的手段是数据校验,只要对比过数据是一致的,那才是真正的一致。MySQL数据校验的手段有很多,其中最经典的是pt-table-checksum。

pt-table-checksum会新建一个临时的checksum表,并且获取与主库有主从关系的所有从库信息。在校验工作时,工具会将该session的binlog格式设置为statement,这样是为了利用mysql的binlog机制,将主库上执行的sql语句同步到从库去。接着工具会以chunk为单位从主库中读取数据和计算校验,将校验结果写入checksum表,这个过程会在一个语句中完成,随后这个语句由于对checksum表进行修改,会被同步到从库并且被从库执行。这样从库也会在自己的checksum表写入校验值。这个时候工具再从库中把checksum值读出,就可以与主库的计算值进行对比。

pt-table-checksum的优势在于使用方便,在经历了多年迭代也有非常好的可靠性保证。但是它的技术限制也是明显,那就是要求被校验的两个库需要是主从关系,同时也要求数据表有索引,因为chunk大小的计算是通过索引完成的。

【案例】

以近期的xx公司迁移到UCloud为例,在数据同步的阶段由于数据库实例众多,需要减少DBA的工作负担而采用了UDTS来进行数据库迁移,但是这样就打破了源和目标库的主从关系,进而导致pt-table-checksum无法使用。当然实际上数据导出-传输-导入-配置主从这样的机械化操作可以通过制作脚本来解决,但是为了迁移而开发一套重用率不高的脚本代码并不明智。这时候sync_diff_inspector工具的优势就体现出来了。

sync_diff_inspector是TiDB团队为了方便用户在MySQL数据迁移到TiDB后对数据一致性进行检查的开源工具,它不要求被校验的两个数据库存在主从关系,也没有对数据表索引的要求,甚至允许源库和目标库有不同的库名和表名,只要有明确的映射,就可以对数据本身进行校验。同时,在sync_diff_inspector发现某一块数据存在差异的时候,会通过二分对比的办法,最终找到实际不一致的行,缩小了疑似不一致的数据范围。

虽然这种相对松耦合的环境下对数据进行校验,可能会出现记录下一些数据不一致,例如主库的某个写入还没有完全即时的同步到从库,这时候进行检查可能会存在数据差异,但是除非源库insert/delete/update操作非常频繁,否则一般期望工具检查发现的差异不会太多。这时候只需要针对检查报告中的少数差异做第二次的手工或脚本校验,就可以确认数据一致性。当然如果一致性检查工具发现有较多数据不一致,我们一是可以用检查工具生成的一致性修复脚本来修复一致性,也可以对通过对数据进行重新同步来完成。

需要留意的是,pt-table-checksum和sync_diff_inspector都是对实体数据进行校验的工具,在数据量较大的情况下校验操作会相对缓慢,不适合在割接时间窗口中操作。在实际项目中笔者测得一个500G的数据库的完整校验耗时大约28小时。在割接时间窗口中,一般通过select max(id)或者select count(id)对数据进行简单对比。

1.2 文件存储同步

1.2.1 文件同步

相比于MySQL,文件作为一种非结构化的存储方式,迁移方法相对较少,也没有太多的数据一致性保障方法。与此同时,海量小文件的处理效率有限一直都是技术难题。

一般来说,文件存储的方式一般是硬盘本地存储或者基于NFS协议的存储服务,这两种存储服务中NFS存储的同步会更困难一些。单个文件的同步是简单的,将文件复制到目标空间然后再对文件计算md5校验和,只要两边的数据是一致的就行。难点在于获知文件是否有发生变化。在linux kernel中可以利用 inotify机制了解到本机对文件的修改动作。

inotify应用在启动的时候除了初始化监听和创建事件队列以外,还会在文件系统操作的函数中加入inotify hook函数以将文件系统事件通知到inotify系统中,这些都是操作系统内核中的系统调用。所以对于NFS而言inotify就失效了,因为相关调用都是本机环境中的系统调用而没有经过网络,挂载了同一个NFS的多台主机没有机制了解对方在什么时候对文件进行了操作。

当然也有一些实现了分布式锁的文件系统,例如vmware的vmfs和oracle的ocfs,可以共享文件系统数据的同时,通过锁机制来实现操作系统对文件变化的感知,但这是另一个故事了。

所以这时候,从业务中对出现变化的文件进行记录就很有必要,因为实际上所有对文件的增、删、改都是业务所需的操作行为。所以在数据同步阶段,我们依然通过rsync或类似方法来同步数据,并且通过业务日志记录发生了变化的文件,最后在割接阶段解析业务日志,将出现过变化的文件做最后的增量同步,从而实现数据追平。典型的组件可以参考FastDFS。FastDFS实现了类似binlog的方式,来记录每个storaged接受到哪些文件的更新,是哪种更新操作。在启动storaged之后,就可以实现自动读取其它同副本关系的storaged的数据来恢复。例如大C表示源创建,小c表示创建副本,大A表示源追加,小a标识副本追加,大D表示源删除,小d表示副本删除等等。

meaEBzb.jpg!mobile 实际生产环境中的fastdfs binlog

1.2.2 文件校验

文件的校验,这里会涉及到存储静默错误的问题。我们回忆硬盘坏道这个概念,就会发现硬盘自己也不知道某个扇区目前状态是否良好,需要专门进行扫描才能确认。一个扇区写了数据,在长久的运行中这一扇区成为了坏道导致不能读出数据,这时候应用不读取就不知道底层数据出现问题,这就是静默错误。

要解决静默错误的唯一办法是全链路数据校验:

在数据上传前,确认数据正常,生成校验和;

上传到某个存储服务之后,存储服务存储文件并且记录这个文件的校验和;

定期对数据进行巡检,重新计算文件校验和并且和记录值比较;

取出数据时,也对数据进行校验和比较,这样才能保证文件数据一致。

因此从技术层面来说建议从一开始就使用带有全链路数据校验功能的服务,自建存储服务的全链路一致性也需要自行建设,否则在迁移后只能通过md5sum这类工具对全部数据进行校验,确保迁移前后数据没有差异,而不保证迁移后的文件依然是访客当初上传的文件。尽管需要做这样的妥协,海量小文件的迁移和校验依然会造成迁移工期的压力。

利用md5sum递归遍历整个目录,生成所有文件的md5结果,可以通过以下命令完成:

find ./ -type f -print0 | xargs -0 md5sum > ./my.md5

相应的,可以通过以下命令对迁移后的整个目录进行递归遍历校验。

md5sum -c my.md5

1.3 对象存储同步

1.3.1 数据同步

对象存储的数据同步和校验的复杂度介于数据库和文件存储之间,因为它基本上是基于HTTP协议的,镜像回源的功能就能派上用场了,即如果一个文件在我们平台上不存在,那对象存储会尝试到源站去获取并保存下来。而相对于InnoDB数据表这中结构化数据,对象存储的数据一致性保障还是相对较弱。

目前市面上各种平台的对象存储服务对S3协议都有较好支持,而通过ufile-import工具就可以将其他支持S3协议的对象存储数据迁移到US3中。虽然US3也支持镜像回源,但是在数据同步的刚开始时,不建议将原平台bucket配置为回源目标之后就将US3作为服务入口来使用起来,因为这个时候US3 bucket中还没有数据,直接使用US3会造成大量镜像回源,一是从而导致整体访问延迟变大,其次也容易出现访问失败的情况。

ufile-import工具与redis协同工作。在数据同步开始前,ufile-import工具会通过S3协议的列表接口,将一定数量的源bucket对象key以及这些key的同步状态记录进redis中。每当一个文件完成从源bucket的下载、缓存和上传到US3后,导入工具就会在redis中将数据标记为已同步。这样在ufile-import工具因为一些可能的原因,例如网络环境不好等问题故障挂起之后,只需要重启ufile-import,它都可以从断点开始续传。

当完成一轮数据导入之后,就可以开始配置镜像回源配置了,这时候直接访问US3也能得到不错的命中率。当然也可以选择再运行一次ufile-import工具,如果这样操作需要注意ufile-import工具原本的功能是断点续传的,所以我们应该把redis的内容清除。

但是直接清理掉redis再重新跑,ufile-import工具的行为是重新加载文件列表并且重写写入US3,这样会导致所有数据都要重新写一次,效率很低。在这个时候,我们可以配置ufile-import工具为文件比对模式,在获取文件列表后将文件都通过HEAD获取文件大小,这时候只要将源bucket HEAD成功,但是US3为not found或者文件大小不同的数据同步到US3即可。在实际的数据迁移实践中,我们可以更加灵活的使用续传和比对模式来提高工作效率。

【案例】

以近期的xx公司迁移到UCloud为例,该公司的CDN和对象存储从金山云迁移到UCloud的过程里面,有一个bucket中存在文件数量达到了12亿,将所有key存储到redis中并不合理,会导致redis数据膨胀,进而对迁移中转主机提出非常高的内存需求。这时候应该从一开始就使用比对模式对数据进行迁移,进而避免不合理的redis内存使用。

1.3.2 数据校验

对象存储的数据校验方面,大多数对象存储都支持给文件提供ETag的Header,且ETag的生成都跟原始数据有一定关系,所以可以根据源平台的ETag计算方式,在下载到文件后对文件进行一次计算,看看ETag是否相符。而ufile-import功能本身也会按照US3的ETag计算规则预先计算我们的ETag,在上传成功后对比US3返回的ETag和导入工具自行计算的值,来实现对数据的校验。

2. 数据规整阶段

2.1 脏数据处理

正如前面提到,为了了解新平台中应用是否能正常运行,一般来说迁移过程中涉及到的应用测试都会尽量使用真实数据,甚至采用流量重放的方法对新系统进行测试,以便通过原平台环境中真实行为的结果来校验新平台用应用是否正常工作。在测试之后,新平台就会出现脏数据,需要对其进行处理。实际上脏数据的处理也有两种思路可以使用。其一是回滚,就是在开展业务测试前先对数据进行备份或者记录还原点。

对于MySQL数据库可以备份binlog然后基于binlog进行回滚,也可以通过云平台能力利用备份直接回滚数据库。对于文件存储和对象存储,文件变更日志的作用就很显著了,所有变更过的文件从日志中解析出来之后从源头重新同步,这样可以避免所有文件的重新同步。当然也可以丢掉全部脏数据,采取跟第一章相同的数据迁移手段对数据进行重新同步,这样虽然慢一些,但是整个数据同步过程就是幂等的,可重复性更强。两种脏数据的处理方式可以视乎数据量灵活采用。

2.2 保障数据一致性

在割接准备阶段时候进行的数据同步,这时候所得到的数据就是割接和割接后的生产数据了,所以需要通过一定的手段,保障数据的持续同步,同时避免数据被意外修改。下面说说几种保障的办法。

2.2.1 基于用户的数据库只读

对于MySQL而言,通过对数据同步和业务设置不同的账户,并且对不同用户分配不同的权限,这几乎是最简单易行的实践方式。设立数据同步账户,赋予增删查改权限和DDL语句的权限,这样可以满足存量和增量数据同步的需要,然后将数据同步账户严格控制只配置给UDTS数据同步工具和sync_diff_inspector数据校验工具。而对于业务应用的配置文件,或者记录到配置中心中的配置,上面所使用的数据库账户就只分配select语句权限,这样就能保障业务应用、脚本或者各种定时任务都无法对数据进行更改。而且这样做还有一个好处,对于一些没有实现数据库重连逻辑的业务应用,这时候数据库是可以正常连接的,这意味着在割接的时候不需要重启应用,而是只需要调整MySQL中业务账户的权限。

对于一些场景,不重启对于割接过程来说是非常重要的。例如由于分布式框架的引入,对象和方法可以轻松的通过RPC获取,这时候业务团队也专注于业务的实现,忽略了底层重连机制的实现。结果就是应用系统成为了一个分布式的紧耦合系统,主机A上某个进程的正常运行需要依赖主机B上进程的正常运行,而且B还不能随便重启,因为重启后A不会重连。这时候如果应用不用重启,那意味着清理脏数据后,应用保持当前的运行状态即可,而不是调查所有应用的启动顺序,在割接时确认数据同步后再按顺序逐个启动,这样对于割接后的业务稳定性和割接操作复杂度都是大有裨益的。

通过数据库只读来保障数据一致性的方式受限会比较多。MySQL有基于用户的只读方法,与此同时redis,sql server,mongodb,Elastic Search,文件存储,对象存储等等组件又有各自不同的只读方法,在组件数量和种类增加以后,这种操作方式的优势会逐渐丧失。所以对于数据库数量在数十个,且只有少数几款数据库应用的时候,数据库只读会是一个很有优势的数据一致性保障方法。

总结一下,数据库只读的方式适用于MySQL数据库且实例数量不多的情况,例如整体迁移以模块化方式进行的情况。另外对于需要尽量减少应用重启操作的系统可以优先考虑。

2.2.2 结束应用进程

前面提到,在一些应用系统里重启应用并不是易事;那自然就有一些应用系统,重启造成的困扰并没有那么大,可以相对自由的重启应用。实际上对于一个系统而言,会有三类程序可能对数据存储进行修改,分别是应用程序和操作系统定时任务脚本,对于数据库而言还需要多加一个定时任务。只需要保证这三类程序都是停止的,那么就可以保证没有同步服务以外的程序对数据进行修改,从而保障数据一致性。

通过这种方法来保证数据不被意外修改的优势在于他是普遍适用的,不管提供存储服务的是数据库或者琳琅满目的各种存储服务,只要进程停了数据就不可能被修改。但是这种处理方法的限制也是很明显的。首先就是应用可以随意重启。更重要的是在分布式环境下面,需要具备批量的启动或者关闭应用程序,以及修改操作系统定时任务的能力,不管是基于ansible或者其他方式,除此以外也需要确保生产环境中应用程序和脚本的统计是正确的,也就是说所有应用程序和脚本都是运维和开发共同知晓的。例如运维为了短时间方便,编写脚本作用在生产环境的数据而不被其他同事所了解,那在停止应用的时候自然也不会被考虑到。

总结来说,结束应用程序的方式适合应用可以各自独立启停,且生产环境应用、脚本和数据库定时任务都完全统计清楚明确的情况下使用。

2.2.3 ACL网络隔离

通过ACL对网络数据存储服务做隔离是一个操作上相对比较简单的方法。简单来说,就是在网络环境上配置ACL,允许数据同步服务连接存储并且禁止其它应用主机连接。这种方法的优势在于规则的套用和解除都相对简单,在数据同步是直接对一整个VPC子网生效,在割接时候又只需要在控制台上解除,对整个子网的存储服务做到批量控制。而且相比于数据库只读和结束应用进程,这两种方法都依赖于运维团队对全系统所有细节的掌握,通过网络ACL进行隔离则可以忽略应用系统细节,而且对所有基于网络的存储服务都能覆盖,可以说完全具备了前面两种数据一致性保护方式的优点。

当然ACL网络隔离的方法也有它的适用场景限制。其中最主要的是这个方法的实施要求运维团队对各个子网的功能划分是清晰明确的,网络入口、业务应用和数据存储分别在不同的子网,所以如果应用习惯了大二层的部署方式,那么网络ACL的批量管理优势就会大打折扣。其次,由于对于应用的网络中断,所以对于没有重连机制的应用,也网络重新开通后依然需要重启应用。最后就是这一方法对于不走网络的应用是无法限制的,例如云硬盘本地存储,这种情况需要以挂载云硬盘的主机为单位去考虑网络隔离。

经过对上面几种保障数据一致性方法的了解,其实我们可以发现这几种方法其实并没有相互冲突的点,可以灵活组合来匹配更多实际环境的要求,例如同时使用结束应用进程和ACL网络隔离。

【案例】

在XX公司的跨云迁移任务中,有几个条件是在前期调研中发现的。首先是数据库实例数量众多,源库和目标库既有自建的也有云平台产品,具体操作方式各有差异;其次是数据存储服务种类众多,除了MySQL以外,还有MongoDB、SQL Server、NFS存储、Elastic Search等,逐个组件去设计读写-只读切换的逻辑需要运维人员很大的精力投入;再次,目标系统对存储和应用有比较好的网段划分,虽然组件众多,但是至少都在相同子网内,适合使用ACL来隔离;最后就是,应用方面也确实没有读写-只读的切换开关,而且也没有实现重连机制。所以,在实际操作过程中,笔者使用了结束应用进程和ACL网络隔离的双重保险,因为应用不具备重连实现的情况下,割接测试前应用至少需要重启一次的,ACL和结束应用的限制都会被接受,与此同时ACL隔离也补充了结束应用的覆盖面,从网络层面保障不会有数据同步组件以外的系统连接到数据存储层面来进行操作。

22AFZbm.jpg!mobile

3. 数据割接阶段

3.1 数据校验时机

不管是整体割接,还是以业务模块为单位的割接,时间窗口大小总是有限的,而且从业务角度也希望割接窗口越小越好。

数据校验最早应该在完成数据规整后才启动,这一点应该是可以简单理解的,因为数据规整前的数据不用作割接后投产,没有校验价值。而在前面数据校验章节中提到,数据校验分为两种,一种是sync_diff_inspector这类实体数据校验,另一种是select max(id)这类元数据校验,两种方法并不冲突,在实际任务中可以灵活安排来减少对割接时间窗口的压力。

【案例】

以近期XX公司迁移到UCloud项目为例,割接时间只有凌晨12点到早上6点的6个小时,中间需要进行应用配置和业务测试,留给数据校验的时间不多,所以早在数据割接之前就启动了sync_diff_inspector对实体数据进行校验。结果数据校验时间和效果都如前预料,最大一个500G数据库的实体数据校验花费了1天多的时间,同时多个数据库的校验也发现了少量的不一致,这一部分不一致经过人工对比后发现发现也实际一致。随后在割接过程中进行元数据校验,结果随着消息队列完成消费和定时任务结束,两边的select max(id)或者select count(id)结果最终一致了。

3.2 割接与回滚

在割接阶段,不得不考虑的一个问题就是回滚,在割接过程中发现数据确实出现了不一致,这时候需要对不一致的范围做合理的评估。如果在割接时间窗口中的元数据校验如果发现不一致,这时候最明智的处理手段就是回滚,而保障原平台没有脏数据则是回滚的基础。

【案例】

以xx公司迁移到UCloud为例,在托管IDC迁移到UCloud混合云的过程中,由于业务依赖较少,所以采用了可以敏捷割接和回滚的业务模块迁移方式。在这一案例的割接实践中,运维团队不仅在为数据库设置了只读,而且也在业务应用中嵌入了只读开关,只要通过配置中心发布开启只读开关即可生效。在数据库只读后就参考数据同步阶段的数据校验方式,对数据或者元数据进行校验,最后在确认应用的读取功能都正常以后再解除目标库的只读,开放业务。在这样的案例中回滚也是相对简单的,如果发现应用的读取功能异常,这时候只需将应用重新部署回原平台,启动和解除数据库只读即可。

而对于需要进行整体割接的任务,割接过程相比于模块化的割接会复杂一些,但是与模块化割接的机理大同小异。在割接过程中先通过停用负载均衡、设置ACL的方式停止业务入口,等待消息队列完成消费数据落地以及定时任务运行完成,然后参考割接准备阶段的方法对原平台数据进行保护。在完成原平台的数据封存后,需要等待同步任务最终完成同步以及对数据进行校验,具体的数据校验方法是参考前面数据校验章节完成的。在确认两边平台数据一致后,就可以停止同步,在新平台启动应用和进行内部测试。

至于回滚操作,本身也是有时间边界的,当新平台业务入口做了灰度开放后就不能进行回滚操作了,因为这时候有很大机率真正的客户数据已经写入到新平台,但是这部分新数据又没有同步回原平台,这样两边数据就是不一致的。

但是一般而言,只要保证迁移两边平台数据是一致的,应用程序大多是应用状态或者代码逻辑问题,相对可控。

本文由UCloud华南架构部团队成员创作

如有疑问或咨询,欢迎留言探讨!


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK