银行核心海量数据无损迁移:TDSQL数据库多源异构迁移方案

为帮助开发者更好地了解和学习分布式数据库技术,2020年3月,腾讯云数据库、云加社区联合腾讯TEG数据库工作组特推出为期3个月的国产数据库专题线上技术沙龙《你想了解的国产数据库秘密,都在这!》,邀请数十位鹅厂资深数据库专家每周二和周四晚上在线深入解读TDSQL、CynosDB/CDB、TBase三款鹅厂自研数据库的核心架构、技术实现原理和最佳实践等。

本文将带来直播回顾第五篇 《高性能、安全稳定、数据一致:TDSQL如何实现数据库异构迁移》

点击图片收看直播回放

我今天的主题是关于TDSQL异构数据同步与迁移能力的建设以及应用方面的内容。整个内容分四个部分:

一是异构数据库方面包括数据分发迁移同步的背景——我们为什么要发展这一块的能力以及现在这部分服务的基本架构;

二是TDSQL异构迁移能力有哪些比较好的特性,以及在实现这些特性的过程中的难点问题和我们提出的特色的解决方案;

三是结合TDSQL现在在国产数据库的一些推广以及应用的经验,我们针对在异构数据迁移或者同步的领域场景最佳实践,也介绍一些好的用法和场景;

四是针对今天讲的内容做一个总结。

事实上,作为国产自研的成熟的分布式数据库产品,TDSQL对内稳定支撑腾讯海量计费业务,对外开放5年来也通过云服务为微众银行等超过500家金融政企机构提供高性能、高可用、高可靠、强一致的分布式数据库服务。TDSQL崇尚良性的竞争,也给予客户强信任的保障:TDSQL具备开放的架构,不仅支持安全快速的数据库数据迁入,同样支持异构数据库迁出。

从客户的需求角度出发,持续打磨产品,是我们一贯的原则。当然,除了支持数据库迁移,多源异构迁移方案也支撑数据汇总、分发等业务场景,这也是TDSQL具备完善的产品服务体系的体现。

1. TDSQL异构数据迁移分发的背景及架构方案

1.1 TDSQL异构数据迁移方案的场景

TDSQL作为一个金融级数据库,面对的更多是金融级场景以及金融机构客户,金融机构往往有一些比较特殊的需求,比如说保险行业,他们基于TDSQL构建业务时会进行一些业务划分,或者基于水平扩展的要求,数据会落在多个分库上等,而有时又需要把多个区域或者多个分库上的数据汇总到一个总库上进行统计分析,TDSQL作为数据层的服务必须具备高性能、准确可靠的将数据实时汇总的能力。也就是说,TDSQL遇到的第一个数据库迁移场景需求就是要支持高速准确进行数据汇总的能力。

二是来自跨城容灾场景的需求。举个例子,腾讯内部金融级业务有跨城容灾的需求,这也是大型互联网公司中常见的容灾级别要求,我们要求业务具备城市级别自动快速容灾切换的能力。比如说在深圳和上海分别有一套数据库并且支撑了相关业务SVR,我们就需要在这两个城市间的数据库DB之间实现数据实时同步,这样有两个好处: 1、这一套实时同步的东西可以在城市级切换的时候快速地将业务切换备城; 2、这一套实时同步做到足够好,比如说实时性更好或者说数据准确度是完全没有问题的情况下,我们可以做到业务的分流,比如有部分的业务是在主城的SVR上,当我们认为主城SVR业务量过大或者说压力太大时候,也可以切换一部分业务流量到备城的SVR上,实现两个城市之间数据层的数据和数据同步。 我们遇到第二个需求就是在跨城容灾或者跨城业务分流、跨城数据同步上我们需要DB侧有这样的能力提供给业务使用。

三是异构的数据分发和迁移。TDSQL作为一个金融级数据库,对外是非常开放的架构,我们支持将数据以各种各样满足业务的方式同步到外面的平台,比如当有一些业务需要在Oracle上跑一些比较老的业务或请求等等;也有一些业务需要把数据同步到消息队列给下游业务使用,比如大数据平台、其他的检索之类,我们可以通过消息队列把数据抽出来。金融机构往往需要数据不仅能够存进来而且能够很好地按照要求分发出去,供下游业务使用,这也是我们遇到比较重要的需求。

针对上面提到的三种场景——数据汇总、跨城容灾、异构数据库间数据的分发和迁移TDSQL针对这些需求构建出一套叫做多源同步的系统。现在介绍一下多源同步的系统是通过什么样的架构来满足我们提到的三个需求的。

1.2 开放的架构:TDSQL多源同步方案架构解读

从图上可以看到有三个组成部分:一是原数据的抽取;二是中间的存储——这是一个消息队列,三是目标实例。这是一个非常典型的CDC架构,通过获取源端数据源的增量数据,通过消息队列,下游消费的逻辑将数据进行分发。从左边看到,这一套多源同步,源端支持MySQL,就是对MySQL系列的DB可以获取它的增量数据;还有Oracle。。抽取完数据增量,比如说binlog日志或者增量数据获取服务抽取到的数据,我们会以一个中间格式存放到消息队列里面;存到消息队列以后,我们自己实现了一个消费逻辑——叫做consumer消费者,它可以实现将这一套存到消息队列的数据按照不同的需求以及不同的目标端类型将数据推送到下游。

目前TDSQL多源同步方案支持的目标端类型有下面这几种:PG, TDSQL, Oracle,还有一部分就是MySQL,另外还可以将增量数据再推往另外一个消息队列,比如说有一些业务可能需要将这套增量的数据推往业务使用的队列组件里面,我们也是支持这样做的。

最后,在这一套同步的数据链路过程中,我们有一个数据校验的服务,包括两个方面:一是增量校验,含义就是会实时校验这一笔数据从源端抽取,到它的增量变化,再到写到目标端之后,这笔数据落库落得准不准确,是不是在正确的目标上写下这笔数据;二是存量校验,可能是一些定时定期去跑批,比如说定期对源和目标的数据进行整体的校验,我们能够主动及时地发现整个数据通路上的问题和错误。

结合我们刚刚说的需求,基于数据同步的跨城双活架构,也是腾讯内部现在在使用的架构。基于数据同步的跨城双活架构是这样的形式:

首先左边和右边代表不同的城市,这里举例左边是深圳,右边是上海。从图上可以看到,TDSQL在SZ这套实例会将业务不断写入的增量数据源源不断地写入本城的消息队列里面。对城的SH也会将自己业务访问的增量数据源源不断写到消息队列里面,同时在各个城市有一套自己的消费服务,这套消费服务会拉取对端的增量数据,也就是说会拉对城的消息队列里面的增量数据进行重放,这样就实现了两套基于数据同步的一套跨城双活。这个双活是有前提条件的——就是两套业务在SZ和SH同时写的时候,它的访问主键一定是分离,在这一套逻辑下面没有办法做到同时对同一条主键进行修改。我们基于跨城的这套双活架构也是要基于主键分离的做法。

2 TDSQL 多源同步方案的挑战和特性

2.1 要求与挑战

介绍完整体架构,我们继续深入拆解下,这套架构所面对的业务场景,都有哪些要求?在这些要求实现的过程中是有哪些难点,并且针对这些难点我们是怎么处理的?以下将介绍这其中的特性、难点、解决方案。

一是高性能:对实时性要求比较高的业务对数据同步的速率有比较高的要求,比如说秒级别等等。但无论如何,在这个互联网时代,这套数据同步要快,不能说加了这套数据同步、异构分发的逻辑以后,它同步的速度非常慢,这肯定是不可以。

二是数据强一致性:在快的基础上,同步的数据一定要准。这套数据同系统,分发的系统把数据从源端抽出来,往里面写的过程中,需要做到原来写出来是什么样的,目标重放就是什么样的,两边的数据一致性一定要有保证,这里面就包含了我们如何规避在抽取链路、重放链路这两个数据链路上的错误;二是如何保证在异常情况下写入的数据一定是对的。

三是服务高可用:这一套同步服务,一定是高可用的,体现在两个方面:1、灾难的情况下,本身消费者的服务能够在假如机器出现一些不可恢复的故障时能够及时地感知并且自动迁移和切换;2、要应对本身常规的扩容——垂直扩容或者水平扩容的伸缩性需求,这也是我们比较强调,这一套同步服务要能够兼容各种灾难情况和常规的运维场景下各种各样的要求来做到服务的高可用。

接下来就针对上面这些点一个一个来看。

2.2 一致性保障

2.2.1 自动化消息连续性检测

从上面的架构图我们可以看出来,整个数据链路比较长,它要先把增量数据拿到,写到消息队列里面去;再从消息队列里面消费出来。生产者这一套服务做的事情就是首先要拿到增量数据,二是要正确地把拿到的增量数据准确地投递到消息队列里面,这里面有两个问题:1、如何判断我拿到的消息——本身的增量数据,是对的;2、我如何确定写到消息队列里面,消息队列存的也是对的。

这就衍生出来两个方式:一是拿到增量消息的时候,我们会根据GTID的特性,检测拿到消息的GTID的连续性,保证拿到这套增量数据的东西一定是准的,比如说GTID上一个拿到的是345,下一个如果拿到的是348,这个时候系统会认为现在拿到这一条GTID跟上一个并不连续,并不连续的情况下我们就要进行容错处理,比如会向主机补偿或者向其他的节点切换补偿等。总结来说,TDSQL在拿增量消息这部分,是具备连续性检测的能力,保证拿到的数据一定是准确、连续的。

二是系统如何保证写到队列里面的数据一定是准?在写到队列过程中有可能出现重复、乱序等情况,TDSQL多源同步方案采用的策略是——利用Kafka本身在写消息的回调通知的特性,我们在将消息推到Kafka的时候,会给每个消息赋予一个连续递增的序列号,通过Kafka回调的写入消息来确定系统写入的消息是不是有序的。举个例子,我们按[5,6,7,8,9]这样的顺序向Kafka生产一部分消息(写),届时收到的消息回调序号也应该是[5,6,7,8,9];当接收完9号这条消息回调的时候,下一条如果收到的回调序号是12、或者11,那么就会认为从9号往后的消息队列消息不是一个有序的消息,这时系统会重新从9这条序号往后的消息重新上报kafka,最终保证写到消息队列里面的数据是没有空洞并且是连续递增的。这是生产者服务在消息连续性异常检测方面我们提供的两种机制。

2.2.2 异常自动切换机制

以上介绍的机制可以保障多源同步、异构迁移中如何检测到错误。那么,检测到错误之后如何处理呢?以下就介绍生产者异常自动切换的机制、切换的条件。

这里面都以TDSQL的实践为例:获取增量日志必须要在一个合适的TDSQL角色上处理,TDSQL本身是一个一主多备的分布式数据库集群,在选择获取数据库增量日志的角色上我们选择从备机上获取。

选择一个合适的备机对增量数据获取来说是非常重要的。当获取增量日志的备机的延迟比较大,或者这个备机本身不存活,或者这个冷备发生了迁移(什么是冷备?离主机的距离最近,或者跟主机的差距最小的备机,我们叫它冷备),这个时候系统就会将解析日志生产者的服务切换到另外一个节点,整个切换流程通过MetaCluster服务协调。也就是说当工作的数据库节点本身的状态发生跃迁之后,其他节点生产者服务就会通过MetaCluster来感知到状态的跃迁,并且适当地启动自己的服务——从一台备机状态跃迁到另外一台备机,而跃迁前的备机的生产者服务会停掉,新的备机生产者服务会自动拉起来。这就是它的切换流程——通过MetaCluster进行下发协调。

切换是基于什么样的触发条件?现在解析到的这台备机本身状态是正常的,比如延迟没问题,存活性也正常,冷备角色一直没有发生变化,但是发现它的binlog不连续。当我们检测到拿到的这套binlog是不连续的时候,就可以认为这里面可能会出现binlog的丢失,这个时候就要发起补偿的操作。怎么补偿呢,通过这个流程给大家介绍一下。

当系统发现解析到这套GTID不连续了,就会向ZK注册一个节点。举个例子,系统现在已经发现拿到的binlog不连续了,于是注册一个补偿节点,包含着“向主机补偿”这样的信号。当主机检测到有这样一个补偿节点时,会将日志解析的角色接管过来并开始工作。

接下来,我们如何确定主机从哪里开始解析日志?我们会从Kafka上读取最后一条消息——最后一条消息包含GTID的信息。这时主机就会把这条消息对应的GTID转化成本地的binlog文件名和偏移量开始解析。

主机的补偿需要持续多长时间?持续一个文件处理的流程。当主机补偿到解析的所在文件结束以后就会退出主机补偿的流程,并将这个角色通过MetaCluster重新下放给备机的生产流服务,而备机的生产流服务接到这个请求以后会重新从Kafka上拉取上一次主机补偿的日志中最后一套消息。如果说找到了对应的GTID,并且往下解析的时候没有发现不连续的情况,这一套补偿流程就算结束,备机会继续在自己的角色上持续地进行增量数据生产。

如果发现从Kafka拉下来的主机补偿日志最后一条本机找不到,就说明这个主机的补偿不完整,有可能备机缺了两三个文件,这个时候会持续向主机进行补偿,通过注册MetaCluster节点的方式一直重复这个流程,直到主机补偿完成,备机在接管角色的时候能够连续顺利地接着解析,本身的日志才认为这套补偿流程已经完全结束——这就是一个通过不断向主补偿日志的方式来进行异常的切换的流程。

2.2.3 幂等重放机制

介绍完生产这套链路之后介绍一下下游的链路——消费,消费的链路中怎么保证数据一致性?首先回顾一下刚刚提到的生产端的数据一致性保障——生产端在实现消息生产的时候实现的是一种at-lease-once的模式进行消息生产,这里面就要求消费服务必须能够确地处理消息重复这个问题,也就是说我们要支持所谓的幂等逻辑。

支持幂等之后有什么好处?在binlog是连续无空洞的前提下,支持幂等机制的消费服务可以从任意一个时间点重放binlog消息,当重放结束以后目标的数据会达到最终一致,这就是消费链路实现幂等的动机和优势。这个机制实现的难点在于要绝对的可靠——重放一定是要百分百没有问题,准确无误。

基于这样的要求以及上游数据写到消息队列里面的现状,TDSQL以此为设计的原则,实现保证按照binlog事件本身的意图对目标实例进行修改。什么叫做按照binlog事件的意图去对目标进行修改呢?

增量数据无非就是三个方面:一是insert的写入,二是更新,三是删除。

1. insert写入

在写入的时候我们是如何做到insert事件幂等呢?一个start进来我们要重放insert:

当它的影响行数大于0,我们就认为这套insert执行成功;如果执行失败,我们认为它可能有一些报错,比如说语法错误或者目标的字段过小,并进行重试的逻辑。

当影响行数等于0,则判定可能会出现主键冲突——insert失败影响行数为0,这里面唯一的可能就是出现了冲突。出现主键冲突的时候这个时候怎么处理?insert这一条数据发生的时候意图是什么?在insert之前DB里面是没有insert这条数据,而当这条insert发生之后,DB里面是有的——按照本身的意图来做,意味着如果发生了主键冲突或者影响行数等于0的情况,里面存在一个相同的记录,这个时候系统会按照insert本身的值拼一个delete操作。这条delete操作下去后,就能保证在这条insert写入之前,目标里面是没有这条数据的;当我这条delete做完之后,再把这条insert进行插入。这个时候如果影响行数大一点,可认为这条insert被按照本身的意图做完了。其实也就是说,要保证这条insert做的时候,只有当前这一条数据——这就是insert本身的幂等。

2. 更新

更新:首先一条update,如果影响行数大于0,可判定这条执行是正常的。如果小于0,则意味着可能出现一些执行错误,比如语法有问题或者字段长度有问题。

如果它的影响行数等于0,有两种可能:一是没有匹配到——进行update时是按照全字段进行匹配的,这一行改之前和改之后所有的字段都在这条消息里面,原始更新也会按照所有字段来去拼装,没有匹配到则意味着某些字段没有匹配到,这个时候会按主键更新——也就是匹配到这些值可能是全字段,执行更新的操作。

如果按照主键更新操作,影响行数还是0的话,则可以判定为出现了主键操作的冲突。这个时候系统就会思考一下,这条update它的语义是什么——update的语义是指这条update执行完以后,目标库里面第一个是没有改之前的值,第二个是有且只有改之后的值,所以我们按照这个语义做接下来的操作,按照所有的唯一键去构造一个删除的操作,操作完了以后再按照update里面改后的,构造一条插入操作,将这条插入操作写入目标DB——如果影响行数大于0,实际可认为这条update就是按照它本身的意图对目标实例进行了修改。

3. 删除

我们来看一下删除的过程。相对于update来说简单多了。这个过程中,delete结束后大于0就成功;小于0就是失败;等于0的时候我们认为它可能没有匹配到行,这个时候我就按照主键操作——因为删除的操作最终的结果就是目标一定没有了当前删除的消息主键所标识的这一行——这条操作完成后,DB里一定没有这行数据,因此仅仅是按照主键进行删除就可以了。这个时候如果影响行数大于0,则删除成功。如果等于0,就认为按照主键去匹配,本身删除不到,匹配不到——意思是本身目标就没有这条要删的主键所标识的数据——所以实际上它的结果跟要做完删除的结果,影响是一样,也就结束这一条删除的幂等。

回顾三种类型的时候,我们比较关注这条数据在执行前后的状态,它执行前是什么样的,执行后是什么样的,我们在重放这条消息的时候,严格按照这个来做,insert就是执行前没有这条数据,执行后有这条数据,如果遇到冲突就先删除后insert,update执行后它的结果,一定没有改之前的值,有且只有改之后的值,删除也是一样,目标里面一定没有主键所标识的这一行在目标实例里面,我们按照这个逻辑设置幂等的流程,就是这样的过程。

2.2.4 跨城数据同步如何规避数据回环

接下来看一下在跨城数据同步如何规避数据回环。跨城的架构中,本城的一套数据实例会把增量数据写到消息队列,对城会有一个服务从消息队列里面把这个数据拉出来——对城的消息也会落到对城的消息队列,本城有一些消费服务会把这些数据拉过来,也就是说数据具有一个环路。如果不做回环检测和规避,比如插入这一条数据,这条数据的目标又插入了,并且也落了一个日志,做了这个日志又写回来,这相当于同一个主键的数据来来回回在写,这样会把数据写脏。

我们是如何来规避跨城数据同步的回环,以及对它进行检测的?TDSQL结合DB内核的改造,通过SERVERID来规避数据在跨城双活数据同步架构里面的回环问题。

假如说左右两端是两个DB,这两个DB对应的SERVER ID不一样:一个是23243,一个是43423。现在有一条叫做insert的数据写入目标,写入目标之后会设置当前这个SERVER ID跟原来的SERVER ID一样——23243的ID。这条insert落到DB里面,会记录成它的对应日志的SERVER ID 23243,而不是记录它本身备城的43423的ID。

当消费服务拿到增量日志——拿到的这条日志所对应的SERVER ID跟目标DB的SERVER ID是一样时,则认为拿到这条日志一定是目标写过来的日志,然后执行跳过的操作。只有当拿到的这条日志对应的SERVER ID跟目标的SERVER ID不匹配的时候,才会把这条数据写到目标里面去。这样一来,才能保证只有是真正业务访问到源端的DB,并落下来的那条日志,才会被成功写入到目标上——这就形成一个通过SERVER ID将环路里面的数据过滤的机制。

2.3高性能保障

2.3.1 有序消息并发重放

现在介绍一下关于高性能的优化实现。

MySQL本身在落日志的时候是有序的消息,就是说binlog是有序的。如果按照binlog的数据来重放,是没有问题的——按照一个事务一个事务进行串行解析。但这会带来一个问题——就是慢。

对于这个问题,TDSQL想办法对有序消息进行并发重放来提升数据同步的效率。采取通过基于row格式binlog日志的hash并发策略来实现。

这个hash策略就是根据表名和主键来做:首先从消息队列拿到数据之后,系统会进行派发,派发过程中根据消息里面的主键和表名进行hash,将消息hash到不同的工作队列。

这样的hash策略有一个什么样的结果?相同表的同一行操作的序列一定会被划分在同一个工作现场,只要保证对某一张表其中固定一行的操作是串行有序的,就认为这套数据在并发重放结束之后数据是最终一致的。

总结而言,TDSQL多源同步并发策略就是按照主键和表名进行hash,保证每一个表里面的固定一行的操作序列在同一个工作队列里面串行化。并发的数据同步和串行数据同步区别就是一致性的问题,可以看到这种并发策略相当于把事务打散。这里面并发重放的时候就会产生事务一致性的问题,有可能会非常小的几率读到中间状态,在数据同步速率有保障的情况下说不会出现这种问题的。如果说这个业务本身对事务一致性要求非常严格——当然我们现在还没有碰到这样的场景。这就是一个有序消息的并发重放。

2.3.2 有序消息并发解析

以上是消费端性能优化的过程,首先就是要写得更快,通过各种优化把hash并发到多个现场去写。那么写完之后,消费端的性能瓶颈在哪里?在解析上。

大家如果有印象的话,我们写到Kafka里面的数据是中间格式——json格式。json格式需要一个解析过程。当我们解决了重放性能瓶颈之后,原始的消息包拿到后解析的过程又变成性能优化的瓶颈。针对这个问题TDSQL同样做了有序消息的并发解析优化。

并发解析的策略就是,维持一个线程池。从Kafka上拉下来的这条消息,本身是一个原始没有解析的包,当拉下来这条消息包时会从这个池子里面捞一个空闲队列,并把这个包给空闲的线程,这个线程拿到这个包以后就开始解析,当它拿到包这一刻就会进入到另外一个busy队列里面。它在忙队列里面会不停地解析拿到的这些原始消息,解析完之后会有一个协调线程,从忙队列面不断把解析线程摘出来唤醒,把解析后的消息再并发地分往后面的工作线程。源源不断从Kafka拉消息,拉完之后就把这些没有解析的消息分给一组线程去解析,这一组线程在解析的时候——虽然解析是并发的,但在被唤醒派发的时候有一个出队的操作——也就是派发是按照顺序派发——这就做到有序消息的并发解析:通过一个忙队列、一个闲暇队列,两个协调线程把整个流程串起来,这样基本解决了在json解析上的瓶颈。

2.4 高可用保障:多机容灾保护

2.4.1 多机容灾保护

现在介绍一下消费者高可用保障。消费者服务本身无状态,所有的任务下发通过MetaCluster实现,可以通过多台机器去部署同步服务,这套容灾机制通过manager进程来实现,也就是说当整个机器掉电,运营这个机器的consumer已经不存活,这个时候这些consumer在MetaCluster上的存活节点的失效就会被其他机器的manager节点感知——认为另外一些机器的consumer已经不存活,这个时候就会把任务接管过来,并且在自己机器上重新拉起这些服务。

二是我们要做到同一个数据同步的链路不能在两台机器上同时拉起,这是一个互斥的要求。高可用机制会通过一些像唯一标识或者当前的分派节点做到,同一个数据同步的任务在被拉起的时候一定是发生在不同的机器上来实现漂移与互斥的操作,这个多机容灾保护总体上就是通过MetaCluster和监控的进程,比如说manager这样的服务进行协调完成,保证在机器级别灾难或者其他灾难情况下这些任务能够在十秒以内成功迁移到其他的存活节点上。

2.4.2 扩容场景的高可用设计

可用性一方面在灾难情况下需要保证服务可用,另一方面则是在扩容等数据库常规运营场景下保证这个数据同步有效且不会中断。

首先来说一下为什么在扩容的场景下,有可能造成数据同步异常?以垂直扩容来说,是相当于重新买了一套实例,然后经过数据的搬迁来实现数据同步的。这个时候我们是通过TOPIC唯一性来保证服务可用。扩容中从一个实例迁移到另外一个实例的时候,两个实例之间关系是什么?它们会往同一个Kafka上TOPIC去打增量数据。新实例打增量数据的起始点是什么?生产者在工作的时候会从Kafka上拿起始点,上一个服务结束的位置就是这个服务开始的位置。

关于水平扩容,则是新扩出一个set来,然后建立数据同步,对重复的分区进行切割和删除。如果现在有两套分布式实例进行数据同步,比如源端有一个分布式实例,这里面对应会有两个同步任务写到目标上,如果对其中一个分片进行水平拆分之后,就会拆出另外一个实例来,这个实例在拆分中有一个数据同步的过程,这个过程会产生问题——在set 3 binlog里面,会有一些set2上写的数据,并且SERVER ID跟set 2一样,如果单纯对set 3新扩出来的分片创建一个数据同步任务,将数据写到目标上的话,我们认为这里面可能会把SET2已经写进去的部分数据重复。这个TDSQL的数据同步服务针对水平扩容的这个场景也是实现了高可用保障,比如我们会针对扩容前的SERVER ID进行过滤,过滤水平扩容前set的原实例的SERVERID,这个跟跨城的回环操作是比较类似的。通过这样的方式,来保证新创建出来的这部分增量数据开始往目标上写的时候,一定是这套扩容流程已经结束了,并且是有真的业务数据写到新扩的分片上来,不会出现同样的数据反复写两遍的情况。

3 TDSQL 多源同步金融级应用场景和最佳实践

上面我们解释了这个模块的特性、难点、解决的方式,现在介绍这些应用场景以及案例,包括TDSQL在多个客户场景中的最佳实践。

3.1 实现业务验证

关于实现业务的验证,比如可以对两个DB进行实时的数据同步。新的业务系统升级时,不可能直接把新的业务系统放到老的DB上直接跑,这时可以把新的业务系统先落到新的DB上做相关业务验证,或者在异构数据库的DB层变更上,把数据先同步到新的DB上来做业务上新老系统并行跑的验证——一方面是保证了原先业务系统的安全性,另一方面也可以让业务切割更加方便,因为数据已经实时同步了。

3.2 实现业务灰度

二是业务的灰度,以张家港农商银行的实践为例,在核心系统上线的过程中,我们把数据通过主键同步到TDSQL或者Oracle上,主库如果发生了一些比较小概率的灾难性实践,这时可以将这个业务系统迅速地切入到备库上,可以是TDSQL也可以是PG、Oracle,相当于是实时的数据备份来形成备份的DB,走备库上把这些业务拉起来在备份的DB上跑起来。

3.3 实现业务割接

三是在实现分布式改造、进行业务割接过程中,可以将单实例的操作同步到分布式的实例上——这个过程先将数据通过多源同步组件同步到分布式的实例上,之后将业务的流量逐渐地从单实例往分布式实例上切,同时在分布式实例上也可以去相关业务验证,这也是我们的应用场景。

3.4 金融级最佳案例实践

我们可以通过多源同步对业务进行分布式的改造,将数据直接通过实时的同步将单实例往分布式的架构上迁移。比如说保险客户通过多个分库、多个分片区或者多个单的业务、逻辑上的划分,把这些数据通过TDSQL这套服务同步到存量库里面。

我们在云上也有一些客户。公有云上,TDSQL的实例是通过公网实时写入自建的IDC里面,不管是Oracle还是TDSQL——写到Oracle我们也支持,我们可以直接把MySQL的DDL转换成Oracle可以兼容的DDL,实现云上的生产业务在跑的同时,本身之前IDC离线业务的老旧业务系统也可以在自建IDC的老实例上运行。

在张家港行实践中,核心交易集群是TDSQL,我们数据同步通过内部的局域网,将存量和增量数据,写入到备份机房,同时也通过全量的数据校验服务保证数据源、目标是完全一致的来做风险控制。当核心交易系统如果出现一些小概率不可恢复的灾难时候,系统可以在短时间内将交易的服务全部切换到备份机房的Oracle上。

四 总结

以上介绍TDSQL对外分发解耦,数据分发、迁移、同步的能力,承载这部分能力的模块叫做多源同步模块,在应对金融级别或者金融场景客户的对外解耦、迁移的需求时候,所衍生出来的,高一致、高性能、高可用这“三高”的特性,并且介绍了针对这些特性我们是如何通过技术手段来实现的。

Q&A

Q:全量检测的效率怎么样?

A:单表的话全量校验一分钟可以校验5个G的数据,但是表和表之间本身是可以并发,也就是说单表一分钟5个G,但是可以多个表并发去跑,这个上限就是机器本身的上限,比如说网卡。这套全量校验也是通过主键去把数据值拉出来走内存去做MD5。这套效率目前来看还可以,但是校验速度也不适宜过快,本身它去拉取数据时候对数据库也是有一些影响的,我们本身做校验的时候也会在业务低峰或者晚上去做。

Q:如何实现抽取binlog到Kafka不丢事务?

A:这就是前面介绍的,系统去做GTID连续性检测,我们知道在记录binlog的时候,GTID一定是连续的,如果不连续则可判定认为它丢了,继而会到主机上补偿。就是通过这样的方式保证我们拿到的数据一定是没问题的。

Q:DDL同步吗?

A:DDL同步。因为DDL同步是会进行一次语法解析,解析出来相关的操作的,比如要改的哪些表、哪些字段,哪些类型需要改,针对目标的不同类型去做类型的转换,将这个DDL重放到目标上。

Q:原抽取和目标回放支持按条件抽取、按条件回放吗?

A:抽取我们支持按白名单去抽。为什么要支持白名单抽?我们原先的策略是全量上报到Kafka,有的时候会带来一些问题,比如说业务去清理一些历史的表,比如说一些流水的大表可能去做日志的删除等等,会批量去做一些操作,这个时候会产生一些疯狂往Kafka上打一些业务并不关心、同步并不关心的数据,这个时候我们也支持源端配白名单的方式,我抽取哪些库表的数据。目标重放更灵活一些,目标重放的时候是通过一个同步规则去配,同步规则本身支持精确匹配,同时也支持政策匹配。精确匹配就是一个表同步到另外一个表,精确匹配支持表名的变换,比如说我在原实例上表名是A表,同步到B实例上表名是B表,这里面强调的是表名可以不一样,但是它的表结构是要一样的。也支持我可以匹配源端多个表同步到目标的一张表里面,也可以支持汇总的方式,就是表名在映射这一块也是比较灵活的。

以上是今天的提问解答。谢谢大家。

TDSQL是腾讯TEG数据库工作组三大产品系之一,在国产数据库领域屡次率先突破,包括助力微众银行搭建首个全行级互联网银行核心系统,以及助力张家港农商行实现传统核心系统数据库首次国产化等。目前,TDSQL已广泛应用于金融、政务、物联网、智慧零售等行业,拥有大量分布式数据库最佳实践。

推荐阅读:

亿级流量场景下的平滑扩容:TDSQL的水平扩容方案实践

流量洪峰成为常态,腾讯数据库如何高性能支撑海量SQL查询?