数据导入与导出(三)|学习笔记

本文涉及的产品
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 快速学习数据导入与导出(三)

开发者学堂课程【PolarDB-X 开源系列课程数据导入与导出(三)】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/1032/detail/15143


数据导入与导出(三)

三、Global Binlog(实时数据导出能力)

image.png

接下来看Global Binlog的整体的overview。

先看右边PolarDB-X会有多个DN节点,每个DN上边有原始的物理Binlog,叫物理Binlog或者原始Binlog。然后CDC的Global Binlog组件会有一个流水线,核心的几个阶段就是Extractor它会解析DN的Binlog,解析完之后会进行排序的操作Merger会把所有DN的经过排Binlog做全局的合并后排序输出输出的Dumper,然后Dumper在对接下游,来提供输出能力。下游就是DTS MySQL、PolarDB-X等等。

左边文字里边来看一下Global Binlog核心特性。首先是兼容事务的,Global Binlog里面所有的通过CN节点来执行事务操作在Global Binlog里面是可以完全还原成它完整事务的。会基于TraceID还有TSO来做全局排序这是一个核心的feature

然后会兼容分布式的DDL,就是我们在执行DDL的时候,每个DN节点上面都会有对应的一些物理的DDL,我们可以做到透明的输出屏蔽掉内部的一些DDL变更的细节

兼容分布式的扩容就是内部做DN节点的增加或者删除操作的时候,对于下游来说是一个完全透明的操作,下游完全感知不到内部的一些变更细节。

至于兼容MySQL生态的主备复制前面已经说过了

接下来看一个演示,Global Binlog可以兼容MySQL。先看一下demo这个demo就是通过Flink-CDC来消费Global Binlog,一个双11大屏的展示

这个视频在之前刚刚完成的发布会上也有对应的内容,如果有看过的同学,可以做复习,没有看过的同学,可以先感受一下这个视频。

视频网址:https://www.bilibili.com/video/BV1WS4y1q7jb/

这个视频只是想让大家来感受一下前面讲的Global Binlog的能力。

接下来讲一下内部的结构外部我们来使用Global Binlog的时候非常简单内部是做了非常多的数据处理和各种各样的一些比较复杂的算法处理。

image.png

可以从图里看一下整个Global Binlog是怎么生成的首先是从用户控制台去执行一个事务到了CN节点CN节点会执行事务里边的各种DmRSQL,这些SQL会最终下发到所有的DN节点来执行,DN节点执行完SQL之后等用户最终提交的时候,在DN节点就会产生Binlog,这个Binlog叫原始Binlog或者叫物理Binlog。右边虚线的部分是整个前期Binlog的内部的总体的结构就是黄色的图。对接每个DN就会有一个Merge Source,Merge Source内部会做一系列的数据处理。Merge Source的右边有一个Merge Joint,这是做全局的排序处理。再到右边,就是Dumper的Leader和FollowerLeader就是主节点follow作为当leader挂掉的时候,follow可以接管,作为一个新的leader。

这个图就是给大家展示一下Global Binlog的总体的大概的生产过程。虚线部分就是生产出来的Global Binlog怎么给下游去消费的比如从下游是一个单键MySQL,然后执行一个Change master的命令,CN就会收到这样的一个命令CN收到这个命令之后就会给CDC这边的Dumper发送对应的请求最终Dumper的leader会把数据源源不断的推送给消费端。

今天的分享重点是事务排序和分布式的DDL是怎么来实现的

image.png

讲排序之前,先熟悉一下PolarDB-X的重要特性,就是全局的时间戳,简称是TSO,左上角的图是TSO的格式高42位是物理的时间,中间的16位是逻辑时间戳,这个逻辑时间戳可以认为是一个自增的系列最后的六位就是保留字节。最终,它是64bit的长度能够保证单调递增。当我们在PolarDB-X去执行完一个事务提交的时候,刚刚演示的那个片子里边说在DN会产生Binlog,我们会把TSO持久化到DNBinlog,然后以名字叫GCN的event来持久化。

image.png

这个截图是从DN的Binlog里边截出来的一部分,可以看到有XA START、XA END、XA PREPARE、XA COMMIT,正好是一个事务整提交的所有的Binlog。红色的框里边就是两个GCN event,上面的是Snapshot TSO,就是在启动的时候拿到的一个Snapshot的TSO,下面的是Commit TSO,这个就是Commit的时候取到的一个全局的时间序列,这个Commit TSO会作为CDC内部对事务进行全局排序的依据。这个是讲了最基本的概念,就是TSO以及它在DN Binlog里边的存储形态。如果想了解更多的细节,可以我们的知乎文章,绿色文字里面展示的这个文章从而了解它内部的一些细节。

接下来就循序渐进来看一下,有了TSO之后,是怎么来排序的

image.png

先看左边图,展示了总体的排序过程,有事务1一个黄色标识事务2TXN-1的TSO是1111TXN-2的TSO是1112。当这两个事务提交完之后,在DN的Binlog里边就会是偏序所示的形态在每一个对应DNMerge Source内部会做一排序,一级排序完之后会保证每个Merge Source输出的都是局部有序的序列然后会再做全局的排序排序完之后就会保证整个事务是全局有序的,按照TSO来做一个全局排序,并且会做事务的合并接着会把这些分布式事务里边的XA START等等一些事件就给它变掉,然后呈现出mysql单机事务的形态BeginCommit然后TSO,大概是这样的流程。

再看一下右边的文字进一步地来一下为什么会有一级排序之所以会有一级排序,是因为在原始的DN里边我们的事务的commit TSO是天然的,并不是有序的,我们内部做了一个名词定义,叫事务空洞,这个空洞就是说对于2PC事务。如果在它的prepare commit之间穿插了其事务的prepare和commit我们就认为这些事务之间是存在空洞的。

因为多个分布式事务是并发提交的,所以说空洞这种现象是不可避免的。有几个小例子,比如P1 P2 C1 C2是有空洞的,之间有其它事务的PC但P1 C1 P2 C2是没有空洞的,P和C之间没有穿插其它事务的操作,我们就认为没有空洞。没有空洞的这种TSO是天然有序的有空洞的TSO就可能是乱序针对这种场景,也要做一级排序。二级排序是非常经典的一个排序算法,就是多路归,依次从各个节点去取事务,然后做排序,完成事务的合输出。

接下来再看一下虚拟TSO虚拟TSO就是我们在完成排序之后,输出到全局Binlog的内容会和原生的mySQL有一些差异,原生的mySQL有begin commit,紧接着下边就是一个begincommit全局Binlog在每个commit后边会有一个cts就是commit Transaction Snapshot,就是一串数字

image.png

这个是我们CDC在基于刚刚讲过的64位的原始的TSO基础上生成的虚拟TSO。它的格式,高19位就是原始的commit TSO中间的19位是分布式事务的事务ID,是全局唯一的然后10位是事务的sequence下边有一个DN的哈希码,标明事务从属的DN是哪个虚拟TSO是因为PolarDB-X在进行事务提交的时候会有很多的优化比如如果发现事务里边只在一个DN上面有操作,那它就优化成了一阶段提交,如果没有开启失误,那就是auto commit单机提交。在这种场景下,在Binlog里面的TSO是并没有记录TSO的所以会在整个排序的过程中,会做虚拟的构造来保证这样的全局有序。这里边的东西比较复杂,一些细节就不展开讲解。大家如果对一些细节感兴趣,可以看一下知乎的文章PolarDB-X全局Binlog解读理论篇里面会有更详细的介绍。大家知道全局Binlog会有一个虚拟TSO,并且会通过ROWS_query event的形态来记录到这个Binlog文件里面去。

以上通过三个ppt讲了一下全局Binlog的一些原理性的东西,以及它是怎么来生成的,接下来就通过具体的例子来看一下整个合并的过程是什么样的。

image.png

已经提前准备好了操作的demo,大家可以看到屏幕上有四个客户端左上角是CN的命令行左上角是一个DN,左下角是另外一个DN的控制台,整个演示就是来看一下去执行事务之后,体是怎么来完成分布式合并

image.png

image.png

先看一下左上角PolarDB-X目前有几个库一个bank库bank下边有一个account的表表里边预置了几条记录然后看一下当前的全局binlog的位点生产到了什么位置。

这是一个局Binlog的文件,它的位点是15121014,

再来看目前DN1的位点1225336,这个是另外一个DN的位点可以看到当前全局Binlog的位点这个是这两个DN的位点。

现在是准备了脚本,开启一个分布式事务事务里边操作也比较简单,有一个账号余21,另外一个账号余21,然后进行commit再看一下事务commit完之后在DN里边Binlog的样子。

image.png

先看DN1里边有一堆提交这里有一个字眼可以看CBC heartbeat这个后边会讲,会有两百毫秒一次的心跳,所以这个日志里边也会有一些比较多心跳的日志。可以看到这个是刚才提交的事务在DN1里边保存的形态可以看一下它的table ID,这个表的名字是带后缀的。因为之前的表是个逻辑表,逻辑表在每DN上边每个分片会对应一个物理表,这个是一张物理表,带一个随机后缀。然后这个是update row event,并且也可以看到XA END、XA PREPARE等分布式事务相关的一些事件。

image.png

再看一下DN2,其实DN2跟DN1是大同小异的。这个时间有些长了,所以里边的心跳会比较多这个里边account的随机后缀和刚才那块是一样的只不过不一样,刚才是bank_000001,这个是000002可以看到这个事务正好执行了两次操作在两个DN里边分别有对应的物理的Binlog

image.png

这时候看一下在全局Binlog里边事务什么样的。可以看到在全局Binlog里边,它的表现形态会非常简单,因为别的里边有很多杂七杂八的一些event,到了局Binlog,正好是一个事务begin commit。有两次提交,有两次更新后边有一个刚刚讲过的CTS。

可以看一下这个account,account已经变成了一个逻辑表名字因为我们在PolarDB-X这边创建的就是一个名字为account的。它在物理Binlog里面是bank_000002.account_y8db这样的名,这块是因为我们在CDC Binlog生产过程中会做一些数据整形操作,把它去翻译成逻辑表,这样下游才可以透明的去消费这些事件这个demo已经演示完毕帮助大家更方便直观地去理解一下刚才讲的那些原理性的内容。

下边紧接着又是一个demo,在讲全局Binlog第一篇ppt的时候,里边说了可以保证事务的完整性,刚才那个视频里边可以看到事务的确已经合并完了。这个视频是一个转账测试的场景深入地看一下我们是怎么来保证了事务的强一致。

image.png

还是四个窗口左上角是PolarDB-X的CN节点右上角是一个单机MySQL左下角跟右下角是一会执行脚本的两个准备好的窗口。

开始还是先看一下当前PolarDB-X里边是一个空库的状态。

这边单击MySQL除了它的系统表没有其任何的业务库。

然后看一下全局Binlog当前的位点,

image.png

接下来做的事情是会在单机MySQL上边来执行Change Master消费PolarDB-X的全局。

image.png

这个链已经创建好了,我们看一下链的状态。目前是已经读完了Binlog所有的状态,正在等待更多的更新。

在PolarDB-X这边创建一个数据库看一下在单机MySQL这边是已经同步过来了,验证一下这个链路的连通线。

这边已经也过来了库名是xxx的库。

接下来要开启一个脚本,这个脚本会做一些数据准备的操作

image.png

data prepare success

然后去PolarDB-X这边的窗口来看一下准备的什么内容

image.png

这边新增了一个bank库bank库里边新增了accounts的表。然后看一下单机MySQL是不是正常同步过来了。

accounts表已经存在了,看一下accounts表里边的内容是什么

里边插入了100条记录每一条记录的余额是10万。同样的,去单机MySQL这边来看一下是不是已经同步过来了

这边的数据也已经同步过来了一共是100条。

接下来看一下总余额。一千万单机MySQL这边也看一下。

不出意外的也是一千万。

下一步就要准备开启转账测试。转账测试里边的脚本也是启动了多个线程,然后不断地在随机的账户之间进行账户的转入转出的操作。

image.png

转账测试已经开始,可以看到它的余额已经发生了变化,一直在变。

单机MySQL这边余额的变化也已经同步过来了。

image.png

接下来程序是一个check data的脚本,会去对单机MySQL的总余额进行验证,不断地去查询它的总余额。

image.png

image.png

程序已经起来,可以看它在不断地输出,它的余额一直是一千万可以看到这个就是强一致的一个表现因为这边事务既能保证完整性又能保证全局有序,所以说,在一些兼容的场景或者说大家在用PolarDB-X的时候,如果下游对于数据的强一致要求比较高基于全局Binlog来做是一个非常好的选择。因为现在目前市面上大部分的数据库并没有这样的能力,大部分都是把数据打散,在下游消费的时候,想保证这样的一种强一致的能力是做不到的。

下边就再看一下PolarDB-X这边余额一千万,

image.png

这边正在不断地去消费,因为我这个配置比较低,源端转账测试已经停掉了,但是因为配置比较低,还要稍微去追一下数据。最终等数据追完之后,我们会再校验一下云端和目标端的checkson。然后更进一步地来验证一下强一致,因为XOR是一样的,是否每条数据都一样,通过checksum的脚本来看一下checksum只要有一条数据不一样,算出来的结果肯定是不一致的,再进一步地来看一下是不是所有的内容都是一模一样再看一下右下角,余额一直都是一千万,并没有出现非一千万的场景这时候开始计算一下checksum

image.png

源端的checksum是4094。看一下目标端是不是已经把所有的数据都已经消费完了顺便可以看一下右边还是在持续地输出

image.png

这时候目标端和端的是完全一致的。

image.png

这个是拆分键变更的场景,我们用任何一个分布式数据库,都会有分区,数据分布就会分布到各个分区。但是它分布完之后,会有一个分区变更,比如有一条数据之前在分区一,但是对这条数据做了变更之后,它的分区件发生了变化这时候这条数据就会从分区一,比如说变到了分区二。分区一变到分区这个行为定义为数据漂移数据漂移会导致什么样的问题?可以看一下这个图有一条PK=1的数据然后发生了一次拆分键变更它的拆分键最开始是X然后变成了Y变成Y之后,这条数据就从了DN1变到了DN2PK1,拆分键变成了Y我们进行这个操作的时候就会在DN1里边直接进行delete的操作然后在DN2里边执行一个insert,最终完成了数据漂移的过程。

图中上面显示的是,没有任何机制保证delete和insert顺序的场景。如果delete在insert前边是没有问题的但是如果恰好insert变到了delete的前边这条数据我们从微端去查的时候就没有了,这个肯定是大家不愿意看到的。刚刚描述的这个场景,其实在我们用传统的这种分库分表中间件作为选型来做分布式分库分表的时候,是一个常见的行为。比如说举一个业务的场景,在打车软件里边,用户下了一个单,它的拆分键是司机的ID,这个订单分配给了司机,但是后来这个订单又发生了一次改派那订单所属的司机就发生了变化在这个业务场景里边,拆分变更因为订单改派发生了产品的变更这个订单最终同步到比如说我们这个库是索引查询库,这时候司机去查这个订单,发现根本就查不到,因为这条数据在传统的分库分表查询下边,没有办法保证deleteinsert的顺序,这样用户下完单之后司机收不到用户的投诉就过来了。

再看一下图中下半部分,下边演示PolarDB-X内核是有Traceid这样设计Traceid一个有序自增的序列号,它的组成是右上角红框里边来展示的样子。有了Traceid,我们就可以规避刚刚描述的场景。通过Traceid实现事务内event的排序这样就能保证顺序。总结一下,就是靠TSO来实现事务之间的排序Traceid来保证事务内不同操作之间的顺序从而来保证事务内的有序性,最终实现了数据的一致性图中右边代码部分就Traceid的形态。

接下来继续看一个Demo来看一下Traceid是怎么工作的

image.png

还是熟悉的屏幕四个框,左上角是一个PolarDB-X控制台右上角是一个DN,左下角又是一个DN,我们直接开始。按照惯例先看一下库现在创建一个数据库,这个数据库名字就叫Traceid

然后再创建一张表这个表名字叫T1有两个字段a和b,按照哈希的方式,以a作为拆分来创建一张表。

表已经创建好了。

看一下这张表的拓扑

image.png

Show topology from是PolarDB-X私有的语法。可以看一下这张名字为T1的表,它有16个分区然后分别分布到了16个物理库。GROUP就是分区名字每一个GROUP会对应一个DN里面物理的库因为没有分表,所以在每物理库上边就有一个物理表。看完的拓扑之后再来看DN里边正好是有8个库1 3 5就是奇数的

image.png

对应了这边GROUP奇数的1 3 5 7 9 11 13 15这几个库。再来看另外一个DN,这个DN里边也是有八个库偶数

还有一个single库。接下来往T1表里边插十条数据

image.png

数据已经插入来看一下数据。10条数据其中a是拆分键我们通过执行计划来看一下因为选中了两条跨DN的数据,就是两条分布到不同的DN的数据可以看到a=1的这条数据看一下它的执行计划。

image.png

它是分布在000001这个物理分区下边然后再看一下2这条数据,

image.png

它是分布在000002这个分区下边。看一下这两条数据,一个是在000001一个是在000002,也去对应的DN上边去看一下是不是这样的,我们看一下DN的Traceid000001这个库下边有没有a=1的这条数据。

再看一下DN2有没有a=2的这条数据

可以看到数据都在,接下来就要进行拆分变更的操作。预先看一下各个DN的Binlog,因为一会操作完之后还要看Binlog里面内容。看完Binlog之后,这边实现了拆分的变更,把a=1这条数据变成了a=2

先不往下看可以停一下,当a=1的数据变成2之后,它这条数据会从DN1漂移到DN2

image.png

也就是说这条数据在这个库里边去查应该就没有了。

image.png

然后在这边去查,应该会有两条a=2的数据。接下来继续看是不是这样的行为。可以看到DN1里边已经没有数据DN2里边多了一条a=2的数据符合预期。

接下来是要看DN1Binlog里面的内容我们看一下拆分变更这一条SQL因为这边只执行一条SQL所以看一下它在DN里面的Binlog是什么样的。耐心等待一下因为里面有心跳,往上翻一下。

可以看到这边有一个delete因为这数据漂移,要从DN里边把数据删掉,我们从DN的Binlog里面也看到了,的确是有delete这样的操作,

然后rows_query这个常规的单机mysql是用来记录事务的查询日志的它在数据复制的时候没有什么太多的影响,通过rows_query这个事件,已经Traceid记录进来了。

image.png

可以看这个Traceid一个编号为2。大家记一下2这个内容我们这个delete操作的Traceid的序号是2

image.png

image.png

接下来看DN2里边Binlog的情况可以看到这边Write_rows_v1,对应的是insert。它的Traceid3。这个也是符合预期的,因为delete肯定是要在前面的,insert肯定是要在后边的。我们在CDC内部程序处理的时候,就会按照23进行排序,然后在事务里边来保证这样的顺序最后还要在全局Binlog里边再看一眼

image.png

可以看到这边是一个单机事务。这个里边记录的Traceid 2 3是取自DN的两个Binlog里边的然后就做了一个排序,和原生MySQL不一样的就是update的操作,在我们的全局Binlog里边,并不是update的event,因为这个是分布式的场景下规避不了的问题,所以说我们会在一个事务里面把它拆分成delete和insert。这个视频就结束了

讲完事务就来讲一下DDL,对于分布式数据库来说,DDL变更其实是一个非常复杂的操作因为它有非常多的节点我们从控制台去提交完一个DDL之后后台我们内核内部在执行用户提交的DDL的时候是非常复杂的因为它有非常多的节点我们在每个节点之间执行一个一步的操作,因为分布式场景没有办法做到原子性,这是一方面,另外一方面,对于全局Binlog CDC这边来说,其实也更复杂因为在DDL变更过程中整个PolarDB-X所有的DDL都是online online的意思就是在执行DDL变更过程中同时不能阻塞DMR的操作,那这样,我们在各个方面上去做变更的时候,DMR的流量还在不断地来进行操作这时候就会生成多版本的数据。

image.png

比如说这个图里边提交了DDLMySQL,分片分别是在TSO100TSO200TSO300的时间点完成的,它们在不同时间点完成了对应分片上的DDL变更。如果在整个100到300过程中DMR的流量还在持续不断的进来,这时候在不同的分片上边就会有不同的数据比如我们在这个时刻分片1的版本的数据是V2,比如说操作是加列,V2的数据已经有新列的数据了,但同样的在分片2上面,它还没有执行加这个操作那它里边的数据就是唯一的版本。在CDC这边汇总完所有DN的数据之后,再往下游输出的时候如果不做处理,它会产生这样的形态,那就是说100和300之间会同时穿插着V1和V2这样两个版本的数据这样会有问题如果下挂的单机MySQL的Schema是强校验的它的schema还没有发生变更,如果我收到了多列的数据,整个同步链路就报错了。所以我们就要解这样的问题。然后我们看一下下面这张图。

image.png

一个Not Online的方案比如说我们去阻塞DMR规避在变更过程中有流量进来肯定是可以实现的,但是这种方案肯定是不可取,因为在现在这个角度去阻塞DMR执行肯定是不现实的那我们选择什么样的方案?选择了整形的方案这个整形方案的原理,如果大家有熟悉Flink,就该会比较熟悉,就是我们会维护schema版本快照的历史就是我们在CDC的内部,会对逻辑表维护一套快照然后对每一个DN上边所有的物理表也维护一份快照维护两份快照在消费各个DN的Binlog的时候,在这个点我拿到了一个DN的数据,我就会去找当前在这个时间线上逻辑schema的形态是什么样的对应的物理schemaBinlog又是什么样的然后它们之间的schema如果是一致的,可以放心地去对下游输出。如果们之间的schema是不一样的那我就要依照逻辑schema为依据来进行数据的整形说起来比较绕口,力求给大家讲明白先看一下文字的描述,

就是时刻的Schema结构称为一个版本DDL变更前的版本叫Vx定义成VxDDL操作后的版本叫Vy它有两种形态,一个Vy兼容VxDDL类型,比如说加列。加列,因为它是新增一个,新增列如果插入老版本的数据一般情况下是不会有问题的Vx兼容Vy的场景指的是变更后和变更前是不兼容的,比如删这种场景。

image.png

上面这张图就非常常见的加列的场景来看。加的场景就是用户提交了一个加列的逻辑DDL,按照分布式的特性,它会在各个分片上面分别在不同的时间点执行执行完之后,内部这边设计了一个叫逻辑DDL打标的操作这样的设计就是等所有的DDL执行完之后,会做一个打标,这个标它本质上就是一个分布式事务,标的目的是让这个事务产生TSO们会依据这个逻辑标来更新CDC里边的逻辑schema的结构

整形的意思就是说无法规避在同一个时刻会出现双版本的数据,但是可以去对数据进行一个整形。比如说在某一时刻,既收到了V1版本的数据也收到了V2版本的数据怎么去整形?比如在提交加列操作这个DDL之前这个表结构有abc三列那CDC里边维护的逻辑表的原数据有三列提交加D这个列之后,在这个物理DDL变更的时候,它是什么形态,比如说在这个分片上面,执行完了DDL的变更它的版本就从V1变成了V2这样的版本,就是说在这个物理DDL执行完之后后边收到的这个分片上面的物理Binlog里边就已经有了D这列。并且这个物理DDL,它是一个autotable add colum,CDC下边收到这个物理DDL变更之后会把物理schema一个实时更新这个物理DDL同步给CDC之后这时候CDC逻辑schema有abc,然后物理对应于这个分片的物理schema已经变成了abcd,然后接下来会收到包含abcd这个数据的这样的event这时候我们就会触发整形,因为整形的这个操作会完全以逻辑schema为基准这时候记录的逻辑schema还是abc,所以说收到加列操作之后会把这个里边d的操作以逻辑schema为基准,把d的操作干掉,从而来保证在双版本数据期间,数据通过整形能始终保证它是和逻辑schema保持一致的。什么时候整形操作会终止?CN内核内部做完达标之后,CDC下游就会收到标操作标操作会包含新增的这个d逻辑schema就变成了abcd,同时各个分的物理schema这时候也是abcd,逻辑的schema和物理schema是一致的,这时候后面的数据也都是V2,就不会触发数据整的操作,从而来保证在进行各种复杂的DDL变更的过程中局Binlog里边通过整形操作来保证DMR event里面的数据和schema是始终保持一致的然后来实现下游消费的时候能去规避掉内部的各种细节,下游消费是完全无感知的。这个比较绕口,大家想了解细节可以看知乎文章——PolarDB-X全局Binlog解读之DDL,里边会有更详细的一些描述。总之就是给大家演示一下这个特性里边的一些处理还是比较复杂的,其实这个和分库分表的场景去比,也是带来了非常大的收益。有过分库分表使用经验的同学应该知道做DDL变更的时候是一个非常头疼的事情。各种操作会非常繁琐,有的时候还要去做上下游的各种数据的验证一个非常耗时耗力的形态。但是如果用PolarDB-X,对于DDL变更来说,就是so easy。

image.png

这个简单来看一下,就是DDL变更的一个总体操作流程这块就不细讲了。下边继续看demo这个demo就是来把上边啰嗦了一堆的简述通过具体的演示来给大家呈现一下。

image.png

还是四个窗口,左上角是一个CN,右上角是PolarDB-X的源数据库,左下角是另外一个DN

我们先看一个这个库叫CDC首尾有下线这个是CDC在PolarDB-X内部的内置的系统库只有高权限的账户才可以看到。这里边有三张系统表一个叫__cdc_ddl_record__一个heartbeat,一个叫instruction。重点来看__cdc_ddl_record__,这个和CDC刚才讲的DDL打标相关的一个系统表。

DDL相关的也有两张表。一个_logic_meta_history一个叫_phy_ddl_history,logic就对应刚才我们讲的逻辑schema的历史快照的信息表physic顾名思义就是每一个分片上边物理schema的快照历史表。现在这三张表一个是在PolarDB-X里边的系统表,然后是在PolarDB-X数据库下边有两张表一共是三张表,保证刚才说的DDL变更当中的整形的操作。建一个数据库,叫ddltest再去创建一张表

image.png

表已经创建好。先看一下__cdc_ddl_record__系统表里边的内容是什么样的

image.png

可以看到里边已经有了一条记录,叫create database ddl,那是因为我刚刚创建了一个ddl的一个ddl操作都会有一个打标数据在里边,大家可以看一下,这里面有一条数据META_INFO保存了这个的所有的拓扑信息这个是建表,再打标。直观的来感受一下:

image.png

这个表比较多,拓扑比较多,因为物理表比较多,我们分区分得多

接下来再看一下右上角两张表里的内容。

image.png

可以看到这边也有一条记录CREATE_ TABLE和database内容其实和打标的数据是非常类似的。再来看一下物理表,这个里边limit了一下,因为物理表非常多,分片非常多,

image.png

这个是物理表的建表SQL,我们会维护到物理的DDL history表里面去。可以看一下这个是DN1,一个上面DN2有对应的表操作。

并且里面记录了一个tso刚才说为什么会打标打标就是借用了一下分布式事务这样的东西通过标事务,我们会取得tso,因为tso一个逻辑时钟就可以以它为基准在时间线上进行逻辑schema物理schema的对比

接下来去做一些操作T1表里面目前是没有数据的不断的插入数据,刚才脚本是启动了一个程序,这个程序不断地往T1表里边插数据,目的是构造一个流量刚才说DDL是online的,整形操作也是online的。构造这个流量的目的,就是一会来触发整形的场景。

image.png

可以看到里边已经插入了一部分数据,其实目前正在源源不断地在往里边进行各种各样的插入操作那接下来要做add column c这样的ddl变更

已经变完成了,刚才大家可以看到的时间是4.95秒,真正的生产环境不会这么慢,因为我这个是测试实例,并且刚才建的那个逻辑表分区非常多,所以说会看起来比较慢一些,这时候已经把流量停掉了 因为DDL变更已经操作完了。刚才在变更的过程中是有DMR流量的这时候看一下我们找了一个DN,左下角刚刚正在演示的DN的节点mysqlBinlog里面看一下。

在看之前,得先去看一下右上角这块是刚才执行的SQL语句

标之后,在这个里边的TSO的情况我们去拿到它的TSO这是一个虚拟TSO,从虚拟的TSO里边,我们要截取到高19位,因为这个是原始的TSO,基于这个原始的TSO去物理Binlog里边看一下因为物理Binlog里面会通过GCN event来保存这个通过mysql Binlog工具来解析mysqlBinlog,去把它输出到3.log里边接下来看3.log通过GCN,就是通过这个TSO来找到这个打标。我们看到有这样的操作对应的TSO,

image.png

这个对应的就是标,接下来演示的是在这个逻辑DDL打标之前物理的表里面的数据,因为加了新的列C列所以肯定会有,并可以看看C的默认值是0,在打标之前各个物理DDL执行完之后它所有的物理分片上就已经有C这个列了同时,刚才还有流量进来。在打标的这个之前肯定会有一些物理表,它的里边已经有C这一列的数据了找到一条数据这条数据已经C这条内容了,它的内容是0

image.png

把它的id记一下,一会我们会基于这个id来做一个校验。接下来再去全局Binlog里边看一眼。这时候我登到了CDC的节点去看一下全局Binlog里面的内容输出到1.log。刚才我们提了uu I,然后通过id去全局Binlog里面看一下去搜索一下,

image.png

发现已经找到了这条数据。可以看到这条数据只有123

但是在左下角1234,刚才讲的整形的操作已经生效了。这样我们就保证了schema和实际的数据之间的一致性。群里面有同学说内容不太好消化,今天讲的内容会比较偏原理不同的课程是针对不同的同学,因为有一些同学在之前那些开源的课程里边说想去更多了解一下原理性的内容,所以今天准备的内容会更偏原理一些。

DDL就讲完了。

image.png

接下来讲节CDC的性能的情况。

一个指标叫Event Per SecondEvent就是刚才我们看得很多demo里面Binlog里的event就是每秒的event写入的情况。对于EPS,我截的图是Sysbench来跑出来的CN DN、CDC的配置就是片子里边展示的这样。EPS在高点可以达到五十万的水平并且EPS是不包含begin和commit的就是Binlog里面有begin commit是不包含这两个的五十万是什么样的水平,对于大部分的这种场景来说,五十万对应的流量是130兆,基本上可以支撑中型的一些互联网公司的流量是绰绰有余的延迟的情况在800毫秒到4秒之间的水平,中间会有一些抖动。原理文章是有介绍的,原理文章在我们的知乎文章里面都可以去搜全局Binlog就可以,里边会有更详细的介绍。如果对内核更有兴趣的同学可以去我们的开源github上搭一个实例出来,然后按照今天讲的内容以及结合这个开文章做些实操来更深入地去了解一下,其实我讲这些内容的目的是体现一下我们整个全局Binlog是经过了一系列的各种设计一系列复杂的操作来给用户达到了这样非常透明的分布式的使用体验。

整形过程中不会导致变更的数据丢失因为整形是以逻辑schema为基准来做的整形所以说整形的这些数据其实都是中间数据都是没有用的因为整形的数据都是在DDL变更过程中产生的。最终打标完成之后才会返回给客户说这个DDL成功了。这时候用户插入的才是它正常的数据。因为在整形过程中逻辑的那个表还没有生效用户插入的字段就会报错,所以整形的数据不会导致变更,会保证数据一致。

相关实践学习
快速体验PolarDB开源数据库
本实验环境已内置PostgreSQL数据库以及PolarDB开源数据库:PolarDB PostgreSQL版和PolarDB分布式版,支持一键拉起使用,方便各位开发者学习使用。
相关文章
|
移动开发 前端开发
前端(十八):移动端H5调用摄像头拍照旋转解决方案
移动端H5调用摄像头拍照旋转解决方案
342 0
|
人工智能 安全
Stable Diffusion:网页版 体验 / AI 绘图
Stable Diffusion:网页版 体验 / AI 绘图
1363 0
|
6月前
|
测试技术 开发者 C++
【Qt 职业生涯规划】Qt 开发者的多元宇宙:从桌面到嵌入式,从2D到3D,你适合哪条路?
【Qt 职业生涯规划】Qt 开发者的多元宇宙:从桌面到嵌入式,从2D到3D,你适合哪条路?
395 1
|
SQL canal 容灾
数据导入与导出(五)|学习笔记
快速学习数据导入与导出(五)
数据导入与导出(五)|学习笔记
|
SQL 算法 关系型数据库
数据导入与导出(四)|学习笔记
快速学习数据导入与导出(四)
数据导入与导出(四)|学习笔记
|
Oracle 关系型数据库 MySQL
数据导入与导出(二)|学习笔记
快速学习数据导入与导出(二)
数据导入与导出(二)|学习笔记
|
SQL 算法 关系型数据库
|
SQL 运维 关系型数据库
|
SQL Oracle Cloud Native
|
开发者
数据导入与导出(一)|学习笔记
快速学习数据导入与导出(一)

相关实验场景

更多
下一篇
无影云桌面