跨云迁移过程中的数据同步及一致性校验实践(二)
在《跨云迁移过程中的数据同步及一致性校验实践(一)》中主要介绍了跨云迁移中数据同步阶段的存储组件 MySQL、文件存储和对象存储的数据迁移过程,本文将重点围绕跨云迁移的数据规整阶段 (清理测试时产生的脏数据) 和数据割接阶段的技术细节进行解析。
** 数据规整阶段
**
1、脏数据处理
正如前文提到,为了了解新平台中应用是否能正常运行,一般来说迁移过程中涉及到的应用测试都会尽量使用真实数据,甚至采用流量重放的方法对新系统进行测试,以便通过对比原平台环境中真实行为的结果来校验新平台应用是否正常工作。
在测试之后,新平台就会出现脏数据,需要对其进行处理。通常脏数据的处理有两种思路可以使用,其一是回滚,就是在开展业务测试前先对数据进行备份或者记录还原点。对于 MySQL 数据库可以基于 binlog 进行回滚,也可以通过云平台能力进行数据库备份和回滚,但是需要注意备份时暂停 UDTS 任务以及其它写入,以及记录 binlog 位置。对于文件存储和对象存储,文件变更日志的作用就很显著了,所有变更过的文件从日志中解析出来之后从源头重新同步,这样可以避免所有文件的重新同步。
当然也可以丢掉全部脏数据,采取与数据同步阶段相同的数据迁移手段对数据进行重新同步,这样虽然慢一些,但是整个数据同步过程就是幂等的,可重复性更强。两种脏数据的处理方式可以根据实际数据量灵活采用。
2、保障数据一致性
在割接准备阶段时候进行的数据同步所得到的数据就是割接和割接后的生产数据了,所以需要通过一定的手段,保障数据的持续同步,同时避免数据被意外修改。下面说说几种保障的办法。
基于用户的数据库只读
对于 MySQL 而言,通过对数据同步和业务应用设置不同的账户,并且对不同用户分配不同的权限,这几乎是最简单易行的实践方式。设立数据同步账户,赋予增删查改权限和 DDL 语句的权限,这样可以满足存量和增量数据同步的需要,然后将数据同步账户严格控制只配置给 UDTS 数据同步工具和 sync_diff_inspector 数据校验工具。
而对于业务应用的配置文件,或者记录到配置中心中的配置,上面所使用的数据库账户就只分配 select 语句权限,这样就能保障业务应用、脚本或者各种定时任务都无法对数据进行更改。而且这样做还有一个好处,对于一些没有实现数据库重连逻辑的业务应用,这时候数据库是可以正常连接的,这意味着在数据割接的时候不需要重启应用,而是只需要调整 MySQL 中业务账户的权限。
对于一些场景,不重启对于割接过程来说是非常重要的。例如由于分布式框架的引入,对象和方法可以轻松的通过 RPC 获取,这时候业务团队也专注于业务的实现,忽略了底层重连机制的实现。结果就是应用系统成为了一个分布式的紧耦合系统,主机 A 上某个进程的正常运行需要依赖主机 B 上进程的正常运行,而且 B 还不能随便重启,因为重启后 A 不会重连。这时候如果应用不用重启,那意味着清理脏数据后,应用保持当前的运行状态即可,而不是调查所有应用的启动顺序,在割接时确认数据同步后再按顺序逐个启动,这样有利于提升割接后的业务稳定性和降低割接操作的复杂度。
然而,通过数据库只读来保障数据一致性的方式受限也会比较多,例如 MySQL 有基于用户的只读方法,同时 Redis、SQLServer、MongoDB、Elastic Search、文件存储、对象存储等等组件又有各自不同的只读方法,在组件数量和种类增加以后,这种操作方式的优势会逐渐丧失。
因此,数据库只读的方式适用于 MySQL 数据库且实例数量不多的情况,例如整体迁移以模块化方式进行的情况。另外对于需要尽量减少应用重启的系统也可以优先考虑这种方式来保障数据一致性。
结束应用进程
前面提到,在一些应用系统里重启应用并不是易事,但有一些应用系统,重启造成的困扰并没有那么大,可以相对自由的重启应用。实际上对于一个系统而言,会有三类程序可能对数据存储进行修改,分别是应用程序和操作系统定时任务脚本,对于数据库而言还需要多加一个定时任务。只需要保证这三类程序都是停止的,那么就可以保证没有同步服务以外的程序对数据进行修改,从而保障数据一致性。
通过这种方法来保证数据不被意外修改的优势在于它是普遍适用的,不管提供存储服务的是数据库或者其他类型的存储组件,只要进程停了数据就不可能被修改。
但是这种处理方法的限制也是很明显的,首先就是应用可以随意重启。其次是在分布式环境下面,需要具备批量的启动或者关闭应用程序,以及修改操作系统定时任务的能力,不管是基于 Ansible 或者其他方式。除此以外也需要确保生产环境中应用程序和脚本的统计是正确的,也就是说所有应用程序和脚本都是运维和开发共同知晓的。例如运维为了短时间方便,编写脚本作用在生产环境的数据而不被其他同事所了解,那在停止应用的时候自然也不会被考虑到。
总结来说,结束应用程序的方式适合应用可以各自独立启停,且生产环境应用、脚本和数据库定时任务都完全统计清楚明确的情况下使用。
ACL 网络隔离
通过 ACL 网络对数据存储服务做隔离是一个操作上相对比较简单的方法。简单来说,就是在网络环境上配置 ACL,允许数据同步服务连接存储并且禁止其它应用主机连接。这种方法的优势在于规则的套用和解除都相对简单,在数据同步时直接对整个 VPC 子网生效,在割接时候只需要在控制台上解除,从而对整个 VPC 子网的存储服务做到批量控制。而且相比于数据库只读和结束应用进程这两种方法,通过网络 ACL 进行隔离则不用依赖于运维团队对全系统所有细节的掌握,对所有基于网络的存储服务进行覆盖,可以说完全具备了前面两种数据一致性保护方式的优点。
当然 ACL 网络隔离的方法也有它的适用场景限制。其中最主要的是这种方式的实施要求运维团队对各个子网的功能划分是清晰明确的,网络入口、业务应用和数据存储分别在不同的子网,所以如果应用习惯了大二层的部署方式,那么网络 ACL 的批量管理优势就会大打折扣。其次,由于对应用的网络中断,因此对于没有重连机制的应用,网络重新开通后依然需要重启应用。最后,这一方法对于不连网络的应用是无法限制的,例如云硬盘本地存储,这种情况需要以挂载云硬盘的主机为单位去考虑网络隔离。
经过对上面三种保障数据一致性方法的对比,可以发现这三种方法其实并没有相互冲突的点,在实际中我们可以灵活组合来匹配更多业务环境的要求,例如同时使用结束应用进程和 ACL 网络隔离。
【案例】
在 XX 公司的跨云迁移任务中,我们在前期调研中发现了几个问题。首先是数据库实例数量众多,源库和目标库既有自建的也有云平台产品,具体操作方式各有差异;其次是数据存储服务种类众多,除了 MySQL 以外,还有 MongoDB、SQL Server、NFS 存储、Elastic Search 等,逐个组件去设计读写 - 只读切换的逻辑需要运维人员很大的精力投入。另一方面,由于目标系统对存储和应用有比较好的网段划分,虽然组件众多,但是至少都在相同子网内,适合使用 ACL 来隔离。最后,由于应用层面没有读写 - 只读的切换开关,也没有实现重连机制。
所以,在实际操作过程中,我们推荐客户使用了结束应用进程和 ACL 网络隔离的双重保险,因为应用不具备重连实现的情况下,割接测试前应用至少需要重启一次,ACL 和结束应用的限制都会被接受。与此同时,ACL 隔离也补充了结束应用的覆盖面,从网络层面保障不会有数据同步组件以外的系统连接到数据存储层面来进行操作。
** 数据割接阶段
**
管是整体割接,还是以业务模块为单位的割接,时间窗口大小总是有限的,而且从业务角度也希望割接窗口越小越好。
1、数据校验时机
数据校验最早应该在完成数据规整阶段后才启动,这一点应该是可以简单理解的,因为数据规整前的数据不用作割接后投产,没有校验价值。而在前面数据校验章节中提到,数据校验分为两种,一种是 sync_diff_inspector 这类实体数据校验,另一种是 select max(id) 这类元数据校验,两种方法并不冲突,在实际任务中可以灵活安排来减少对割接时间窗口的压力。
【案例】
以近期 XX 公司迁移到 UCloud 项目为例,割接时间只有凌晨 12 点到早上 6 点的 6 个小时,中间需要进行应用配置和业务测试,留给数据校验的时间不多,所以早在数据割接之前就启动了 sync_diff_inspector 对实体数据进行校验。结果数据校验时间和效果都如前预料,最大一个 500G 数据库的实体数据校验花费了 1 天多的时间,同时多个数据库的校验也发现了少量的不一致,这一部分不一致经过人工对比后发现实际一致。随后在割接过程中进行元数据校验,结果随着消息队列完成消费和定时任务结束,两边的 select max(id) 或者 select count(id) 结果最终一致了。
2、割接与回滚
在割接阶段,不得不考虑的一个问题就是回滚,在割接过程中发现数据确实出现了不一致,这时就需要对不一致的范围做合理的评估。如果在割接时间窗口中的元数据校验如果发现不一致,这时候最明智的处理手段就是回滚,而保障原平台没有脏数据则是回滚的基础。
【案例】
以 xx 公司迁移到 UCloud 为例,在托管 IDC 迁移到 UCloud 混合云的过程中,由于业务依赖较少,所以采用了可以敏捷割接和回滚的业务模块迁移方式。在这一案例的割接实践中,运维团队不仅为数据库设置了只读,而且也在业务应用中嵌入了只读开关,只要通过配置中心发布开启只读开关即可生效。在数据库只读后就参考数据同步阶段的数据校验方式,对数据或者元数据进行校验,最后在确认应用的读取功能都正常以后再解除目标库的只读,并开放业务。在这个案例中回滚也是相对简单的,如果发现应用的读取功能异常,这时候只需将应用重新部署回原平台,启动和解除数据库只读即可。
而对于需要进行整体割接的任务,割接过程相比于模块化的割接会复杂一些,但是与模块化割接的机理大同小异。在割接过程中先通过停用负载均衡、设置 ACL 的方式停止业务入口,等待消息队列完成消费数据落地以及定时任务运行完成,然后参考割接准备阶段的方法对原平台数据进行保护。在完成原平台的数据封存后,需要等待同步任务最终完成同步以及对数据进行校验,具体的数据校验方法是参考前文中数据校验方法完成的。在确认两边平台数据一致后,就可以停止同步,在新平台启动应用和进行内部测试。
至于回滚操作,本身也是有时间边界的,当新平台业务入口做了灰度开放后就不能进行回滚操作了,因为这时候有很大机率真正的客户数据已经写入到新平台,但是这部分新数据又没有同步回原平台,这样两边数据就是不一致的。但是一般而言,只要保证迁移两边平台数据是一致的,应用程序大多是应用状态或者代码逻辑问题,相对可控。
总结
以上就是笔者关于跨云迁移在数据同步、规整和割接过程中保障数据一致性的一些实践和思考,希望对遇到同类问题的大家有所帮助。当然,本文所阐述的数据迁移同步的解决方案也适用于本地 IDC 迁移上云的场景。
声明:文章来源于 UCloud 技术,作者 iShadow。本平台只用于分享和交流不作商业用途,如侵权请及时联系我们删除。
测试