开发者学堂课程【PolarDB-X 开源人才初级认证培训课程:数据导入与导出】学习笔记(一),与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1075/detail/15547
数据导入与导出
内容介绍:
一、PolarDB-X CDC
二、Global Binlog
三、Replica
四、Future Plan
一、PolarDB-X CDC
PolarDB-X CDC 数据导入与到处,主要是CDC的Global Binlog和Replica两部分,一半原理一半做 DEMO 演示。
1.Architecture
整体的PolarDB-X CDC架构如上图所示,CDC是蓝色的两个节点,默认的情况下,CDC有两个节点,两个节点互为主备,组成了一个PolarDB-X CDC的子集群,CDC,Change data capture,在使用PolarDB-X CDC数据库的时候,CDC是一个可选的能力,去部署PolarDB-X CDC实例的时候,如果没有数据导入或者导出需求,是可以不去选装CDC,可以节省一些成本。
2.Key Features
核心feature,最左边是数据流入,可以上游对接兼容MySQL任何的数据库,只要它有Binlog的输出能力,比如原生的MySQL、RDS、PolarDB-X,都可以作为数据流入的一个源。最右边是一个数据流出的能力,因为提供了Global Binlog,下游只要可以消费云原生MySQL的任何的中间件,或者任何的数据库产品,都可以来对接PolarDB-X的数据流出能力,中间是一个生态兼容,数据流入和数据流出是完全和MySQL兼容的,如果以前用的一些中间件或者一些技术架构是对接的MySQL。如果想用PolarDB-X,之前所有遗留的架构或者产品都可以无缝迁移到PolarDB-X数据库上面,是非常成本很低的操作
二、Global Binlog
1.Overview
Oracle暂时是不可以的,目前PolarDB-X主推的兼容MySQL生态,所以目前Oracle对接不了。
PolarDB-X会有N多个的DN节点,每个DN上是有原始的个物理Binlog,或称原始Binlog,CDC的全基Binlog组件有一个流水线,核心的几个阶段Extractor它会解析DN的Binlog,解析完之后会进行一些排序的操作,Merger会把所有DN上经过排序的Binlog做一个全局的合并,合并后排序输出,输出Dumper,Dumper对接下游,提供输出能力,下游可以是DTS、MySQL和PolarDB-X等。
全球Binlog的核心特性:
首先是兼容事务,Global Binlog里边通过CN节点来执行的事务操作在Global Binlog里边是可以完全还原成完整事务的,会基于有一TraceId、TSO做一个前期排序,这是一个核心的feature,会兼容分布式的DDL,在执行DDL时,每个DN节点上都会有对应的物理的DDL,可以做到透明的输出,屏蔽掉内部的一些DDL变更的细节,兼容分布式的扩缩容,内部做DN节点的增加或者删除操作的时候对于下游是一个完全透明的操作,下游完全感知不到内部的一些变更细节,下边是兼容MySQL生态的主备复制。
2.Demo演示
Global Binlog可以完全兼容MySQL,Demo通过FLink-CDC来消费Global Binlog,一个双11大屏的展示,视频在之前刚刚完成的发布会上也有对应的内容
数据大屏在业务展示和决策中有非常重要的作用,通过PolarDB-X Global Binlog 能力与Flink CDC MySQL connector能力模拟双十一的交易大屏,首先,通过MySQL Client连接PolarDB-X看一下里面库表情况
可以看到,除系统库外,PolarDB-X里面有两个库,一个是mydb业务库,一个是gmvdb,用来缓存Flink 的实时计算结果,首先看一下mydb
里面有一张订单表,查看表结构,可以看到这张表包含订单id价格等信息
查看gmvdb,里面有gmv这张表,查看表结构
其中包含gmv交易总额和orders总订单量两列
连接Flink,在Flink中创建两张表,这两张表与PolarDB-X的两张表对应,首先看orders这张表
采用的是mysql-cdc connector,即Flink会将上游的PolarDB-X完全当作一个MySQL,另一张表gmv采用jdbc connector
创建orders这张表,创建完成,测试它的连通性
联通正常,创建第二张表,创建完成,创建实施计算任务,该任务会从订单表中获取所有的价格进行一个加总,并将所有的订单进行一个count计算,最后将结果写回gmv这张表,执行SQL以创建任务
任务创建完成,将实时计算结果展示到前端大屏
大屏已经展示当前的系统的状态,通过在源端写入大量的订单来模拟双十一的零点时刻,随着订单的写入,交易大屏开始翻滚
3.Runtime Architecture
内部的结构,外部来使用Global Binlog的时候,就非常简单,其实内部是做了非常多数据的处理和各种各样的一些比较复杂的算法处理,Global Binlog是如何生成,查看上图,首先是从用户控制台去执行一个事务,到了CN节点,CN节点会执行事务里边的各种DMR的SQL,SQL会最终下发到所有的DN节点来执行,DN节点执行完SQL之后,等用户最终提交的时候,在DN节点就会产生Binlog,Binlog是原始Binlog或者物理Binlog。右边虚线的部分是整个前期Binlog内部总体的结构,就是黄色的图,对接每个DN会有一个Merge source,Merge source内部会做一系列的数据处理。Merge source的右边有一个Merge joint,做一个全局的排序处理,再到右边是Dumper leader和follower ,leader是主节点,Follower是备节点,leader挂掉的时候Follower可以接管,作为一个新的leader。上图就是展示全局Binlog总体的生产过程,虚线部分,生产出来的Global Binlog如何给下游去消费的,从下游比如是一个单机MySQL,执行一个change master命令,CN就会收到这样的一个命令,会给CDC的Dumper发送对应的请求,最终Dumper的leader会把数据源源不断的推送给消费端,分享重点是事务排序和分布式的DDR是如何来实现的。
4.Transaction Sort&Merge
熟悉PolarDB-X的重要特性是全局的时间戳,简称TSO。上图是TSO的格式,高42位是一个物理的时间戳,中间的16位是逻辑时间戳,逻辑时间戳可以认为是自增的序列,最后的6位是保留字节,最终它是64比特的长度,能够保证单调递增,当在PolarDB-X去执行完一个事务提交的时候,刚刚演示的视频中里边在DN会产生Binlog,会把TSO持久化到DN的blog,以名字为GCN的一个event来持久化。
上边截图是从DN的Binlog里边截出的一部分,有XA start、XA end、XA prepare和XA commit,正好是一个事务完整提交的所有的Binlog,红色的框中是两个Gcn event,上边是snapshot TSO,就是事务启动时拿到的snapshot TSO,下边Gcn是一个commit TSO,commit时的一个全局的时间序列,commit TSO会作为CDC内部,对事务进行全全局排序的依据。最基本的概念TSO以及它在DN Binlog里边的存储形态想了解更多的细节,可以知乎文章《PolarDB-X全局时间戳服务的设计》。
上图展示了总体的排序过程,有一个事务1,有一个黄色标识的事务2。事务1的TSO是1111,事务2是1112,当两个事务提交完之后,在DN的Binlog里边会是这样的一个形态,事务1提交了,它的start、prepare、commit、TSO,在每一个对应DN的Merge source内部会做一级排序,一级排序完之后,会保证每一个Merge source输出的都是局部有序的序列,再做一个全局的排序,全局排序完之后会保证整个事务是一个有序的,按照TSO做一个前期排序,并且会做事务的合并,会把分布式事务中的XA start等等一些事件就变掉,呈现出MySQL单机事务的形态,commit跟TSO,大概是这样的一个流程。为什么会有一级排序,因为在原始的DN的Binlog里边事务的commit TSO,天然并不是有序的,内部做了一个名词定义——事务空洞,空洞对于一个2PC的事务,如果在其prepare、commit之间穿插了其他事务的prepare和commit,就认为这些事务之间是存在空洞的,因为多个分布式事务是并发提交的,所以空洞种现象是不可避免的
举例:比如有空洞是P1P2C1C2,P是prepare的简称,C是commit简称,P1跟C1之间有其他事务的提交,认为是有空洞,连续的P和C之间没有穿插其他任何事务的操作,就认为没有空洞,没有空洞的种场景TSO是天然有序的,有空洞的TSO是乱序的或可能是乱序的,针对这种场景,所以要做一级排序,二级排序就是非常经典的排序算法,就是多路归并,依次的从各个节点去取事务做一个排序,完成一个事务的合并并输出。
虚拟TSO是在完成排序之后,输出到Global Binlog的内容和原生的MySQL有一些差异,原生的MySQL有begin commit,紧接着下边就是一个begin commit,PolarDB-X的Global Binlog里面,在每一个commit后边会有一个CTS,就是commit Transaction snapshot,就是一串数字
是CDC在基于刚刚讲过的64位的原始TSO基础上生成的虚拟TSO,格式是高19位,就是原始的commit TSO,中间的19位是分布式事务的事务ID,是全局唯一的,还有一个事务的sequence,下边有一个DN的哈希玛,就是标明事务从属的DN是哪个,为什会有一个新的TSO,是因为PolarDB-X在进行事务提交的时候,会有很多的优化,比如如果发现事务里边只在一个DN上面有操作,就优化成了一阶段提交,如果没有开启事务,就是auto commit单阶段提交,在这种场景下的话,在Binlog里面的TSO,并没有记录TSO的,所以会在整个排序的过程中,做一个虚拟的构造来保证前期有序,里面的东西比较复杂,细节不展开讲,如果对一些细节感兴趣,可以看一下知乎的文章。虚拟TSO会通过一个Rose event的形态来记录到个Binlog文件里面,上边是通过三个Global Binlog的一些原理性的东西,是如何生成的,
接下来通过一个具体的例子看整个合并的过程。提前准备好了一个操作的DEMO,有四个客户端
左上角是CN的命令行,右上角是一个DN,左下角是另外一个DN的个控制台,整个演示来看执行一个事务之后具体是如何完成的分布式事务的合并。左上角PolarDB-X目前有几个库,有一个bank库,bank下边有一个account表,表里边预置了几条记录,看一下当前的Global Binlog的位点生产到了什么位置
是Global Binlog的一个文件,位点是151121014的位点,目前DN1的位点,125336,左下角是另外一个DN位点,第一个是当前Global Binlog的一个位点,下面两个是两个DN的位点,准备了一个脚本,开启一个分支事务,事务里边操作也比较简单,有一个账号余额加1,另外一个账号余额减1,进行commit,已经commit,看一下事务commit之后,在DN里边的Binlog是什么样的。先看DN1
里边有一堆提交,里边有一个字眼可以看CDC heart bit,会有200毫秒一次的心跳,日志里边也会有一些比较多的心跳的一些日志。
这个提交的事务在DN1里边保存的形态,可以看一下它的table ID,表的名字带一个后缀的,因为刚才逻辑表在每一个DN上边,每个分片会对应一个物理表,这个是一张物理表带一个随机后缀,这个是一个update update event,并且也可以看到XA end、XA prepare等分布式事务相关的一些事件。再看一下DN2
时间有些长所以里边的线电会比较多,里边看它的随机后缀和刚才是一样的,只不过库不一样,刚才是BANK000001,这个是000002,事务正好也是执行了两次操作,在两个DN里边分别有对应的物理的Binlog,看一下在Global Binlog里边个事务是什么样的
可以看到在Global Binlog里边,它的表现形态会非常简单,因为里边有很多杂七杂八的event,Global Binlog正好是一个事务begin commit,有两次提交,有两次更新,后边有一个虚拟TSO,account已经变成了一个逻辑表名字,因为在PolarDB-X创建的就是一个名字叫account,它在物理Binlog是account_y8db名字,因为在CDC Global Binlog生产过程中会做一些数据整形的操作,把它翻译成的逻辑表,下游才可以透明的去消费这些时间,演示结束,帮助更方便、更直观的理解原理性的内容。
在讲Global Binlog第一篇PPT时,可以保证事务的完整性,事务的确是合并完了,会找一个转正测试的场景,更深入的看一下是怎么来保证事务的强一致。还是四个窗口,左上角是PolarDB-X的CN节点,右上角是一个单击MySQL,左下角跟右下角是一会要执行脚本的两个准备好的个窗口。当前PolarDB-X里面是一个空库的状态,单击MYSQL。除了系统表,也是没有其他的任何的业务库,Global Binlog当前的位点
接下来要做的事情是会在单机MySQL来执行change master来消PolarDB-X的Global Binlog
链路已经创建好,看一下链路的状态。
目前已经读完了所有的Binlog,正在等待更多的更新,继续在PolarDB-X创建一个数据库
查看在单机MySQL是否同步,验证一下链路的连通线,已经过来一
个库名是xxx的库,开启一个脚本,脚本会做一些数据准备的操作,
data prepared success
PolarDB-X窗口查看内容,新增了一个bank库,库里边新增了一个count表,单机的SQL也正常同步,bank表里面插入了100条记录
每一条记录的余额是10万,单机MySQL已经同步,一共是100条。
总的UR是一千万,MySQL也是一千万,下一步就要准备开启转账测试,转账测试里边的脚本也是启动了多个线程,不断的在随机的账户之间进行账户的转入转出的操作。
转账测试已经开始,余额已经发生变化,一直在变,MySQL余额的变化已经同步,接下来程序是一个checkData的脚本,会对MySQL的总余额进行一个验证,会不断的查询它的总余额
程序运行在不断的输出,余额是一千万一直在输出,可以看到这就是强抑制的表现,事务既能保证完整性,又能保证全局有序,在一些兼容的场景,或者在用PolarDB-X的时候,如果下游对于数据的强抑制要求比较高,基于Gobble Binlog做是一个非常好的选择,因为现在目前市面上大部分的数据库,并没有样的一个能力,大部分都是把数据打散,在下游消费的时候,想保证一种强制强抑制的能力是做不到的,PolarDB-X余额是一千万
这边正在不断的消费,因为配置比较低,原端的转账测试已经停掉了,但是因为配置比较低,还要去稍微追一下数据,等数据追完之后,会再校验一下原端和目标端的checksum,更进一步的来验证强抑制,因为余额是一样的,是不是每条数据都一样,通过checksum的脚本来看一下,只要有一条数据不一样,算出来的checksum肯定是不一致的,再进一步的来看是不是所有的内容都是一模一样,右下角余额一直都是一千万,并没有发生非一千万的样一个场景。计算checksum,云端的checksum4094,查看目标端是否将已经把所有的数据都消费完,顺便可以看一下右边还是在持续的输出
重放,重新查看,目标端和原端的 checksum,是完全一致的。
这是一个拆分键变更的场景,用任何一个分布式数据库,都会有分区,有分区,数据分布就会分布到各个分区,但是它分布完之后会有一个分区变更,比如有一条数据之前在分区1,但是对这条数据做了一个变更之后,它的分区键发生了变化,这条数据就会从分区1变到了分区2,它从分区1变到分区2,把它定义成这个行为是数据漂移,数据漂移的话会导致一些问题,如上图,有一条PK=1的数据,发生了一次拆分键变更,它的拆分键最开始是X,然后变成了Y,变成Y之后,这条数据就从DN1变到DN2,PK=1,拆分键变成了Y,在进行操作时,会在DN1里边执行一个delete操作,在DN2里边执行一个insert,最终完成数据漂移的过程。
上面图显示的是没有任何机制保证delete和insert顺序的场景,如果delete在insert前边是没有问题,但如果恰好insert变到了delete前边,这条数据从去查就没有,这是不愿意看到的,刚刚描述的场景,其实用传统的种分控分表中间件作为选型,做分布式分控分表的时候是非常常见的一个行为,比如举一个业务的场景,比如把拆软件里,用户下单,有一个订单他的拆分件比如是司机的ID,订单分配给了一个司机,但是后来订单又发生一次改派,订单所属的司机就发生了变化,在这个业务场景里边,它就会出现样的一个场景,是拆分件变更,因为订单改派发生拆分件变更,订单最终同步到比如库是一个索引查询库,司机去查订单发现根本就查不到,因为数据在传统的场景下没有办法保证delete和insert的顺序,订单用户下完单之后,司机收不到,用户的投诉就过来了,上图下面的图,PolarDB-X内核有一个TraceId的设计,TraceId是一个有序自增的序列号
它的组成是红框里边展示的,有了TraceId,就可以来规避刚刚描述的场景,通过TraceId来实现事务内event的排序,就能保证顺序。总结一下,靠TSO来实现事务之间的排序,靠TraceId来保证事务内不同操作之间的顺序,从而来保证事务内的有序性,最终实现了数据的一致性。