6月5日在“国产数据库硬核技术沙龙-TDSQL-A技术揭秘”系列分享中,5位腾讯云技术大咖别离从整体技术架构、列式存储及相干执行优化、集群数据交互总线、Fragment执行框架/查问分片策略/子查问框架以及向量化执行引擎等多个方面对TDSQL-A进行了深刻解读。

其中腾讯云数据库高级工程师-陈再妮,对于“TDSQL-A海量数据交互之道及企业级数据库能力”,进行议题分享。没有观看直播的小伙伴,可不要错过本次分享内容的文字实录。

以下内容为现场分享实录:

TDSQL-A 是腾讯基于开源数据库PG自主研发的分布式剖析型数据库系统,最早可追溯到08年,到当初曾经经验10余年打磨,团队领有数十篇外围研发专利。TDSQL-A 全面兼容 PostgreSQL,高度兼容 Oracle 语法,采纳无共享架构,反对行列混合存储,在具备业界当先的数据分析能力的同时还具备残缺反对分布式事务ACID的能力。

上面是TDSQL-A的总体架构,两头是数据交互总线,它将整个分布式集群的各个节点有机地联结起来,负责整个集群中所有节点数据的交互。这个数据交互总线,咱们称它为FN(forward node),FN通过业界当先的集群内通信技术,能够反对上千台节点的超大规模集群,十分实用于 PB 级的海量 OLAP 场景。

1

FN设计与部署形式

1.1 原分布式执行框架

对分布式系统来说,数据重散布是无奈防止的,就如下图中所示的,当某个表的hash join的字段不是散布键时,咱们就须要进行数据重散布。在数据重散布的过程中,咱们须要创立相应的连贯和过程。

假设咱们零碎当初有N个DN,DN即数据节点,在数据重散布过程中每个DN都要跟其余DN之间建设连贯,那么这个零碎中的连接数就是NN。如果有M层Join,那就是MNN个连贯,再假定咱们零碎的并发数是X,在这个根底上再乘以X,那就是XMNN个连贯。

这样的话,当整个集群规模达到千百台、并发为上百个时,整个集群的连接数将会有上亿个。这个连接数是十分宏大的,此外,如果连贯太多创立回收socket也会成为瓶颈。为了解决这个问题,咱们引入了数据交互总线节点FN(forward node)。

1.2 优化后的分布式执行框

咱们在每台服务器上都部署了一个FN,用于跟其余节点之间的数据通信,图中用红色标记的节点就是FN。FN通过FID,src_node_id, dest_node_id来进行网络数据路由。而FID则标识了查问的RemotSubplan。整个业务逻辑归纳起来就是,我是谁,我从哪里来,要到哪里去。

通过这种路由形式,在零碎中有N个DN数据节点的状况下,不论整个零碎的查问有多简单,并发量有多大,整个集群之间最多有服务器个数N*(N-1)个socket连贯,无效升高了整个集群内的连贯数量。此外,本机节点通过共享内存进行数据交互能够不走网络,这样就能够反对超大规模的集群部署。

1.3 部署构造

为了将服务器资源充分利用起来,个别状况下咱们会在服务器上部署多个CN或者DN。比方下图中这个服务器上就部署了两个DN,而FN咱们只须要在每台服务上部署一个即可,也就是说,一个FN能够服务于这个机器上的多个CN/DN节点的通信。

FN实际上也是一个postgres过程,与CN、DN或者GTM属于平级的关系。FN过程在启动时,能够采纳参数-Z forwardnode来标识该过程为FN。把FN设计为postgres过程的长处在于能够复用PG的元数据管理、参数配置等。退出FN的次要目标,在于缩小DN之间、CN和DN之间数据交换时创立的连贯,从而保障大规模集群下网络连接不成为瓶颈。

1.4 通信音讯

在分布式系统中,节点之间的音讯个别分为两种类型;一种是管制音讯,走的是控制流;一种是数据音讯,走的是数据流。

在TDSQL-A中,管制音讯个别用于元数据的散发治理和命令的传递。传递形式跟PG是统一的,采纳的是Libpq协定。数据的传输通过FN来进行,采纳的是TCP/IP协定,FN之间建设Socket连贯,来进行数据的传送。

管制音讯的利用场景能够归为以下三类:

CN向DN下发plan或者sql,commit/rollback等执行命令
CN/DN向本机FN发动启动时节点的注册/退出时节点登记申请
不同机器上的FN之间互相注册/登记申请(FN跟FN之间,也是通过注册、登记进行交互的)

对于数据音讯,它须要通过FN来进行转发。这里咱们又能够把它细分为不同服务器之间、同一服务器外部这两种利用场景。

在不同服务器之间,CN、DN只须要与本机的FN进行交互,不再须要与其余CN/DN之间进行连贯。FN依据目标节点的ID,去和目标节点的FN进行连贯,这是服务器之间的转发。

在同一服务器外部,CN/DN与FN通过共享内存来进行通信。比如说,DN通过共享内存将数据传递给FN,FN再通过共享内存将数据传输到本机器上的其余DN,这样就不须要进行网络通信。

不论是在服务器之间,还是同一个服务器外部,都是由FN进行解决,这样的话,能够做到数据通信的对立治理。咱们也不必放心FN会成为瓶颈,因为在FN外部也能够配置为多线程进行运行。

1.5 集群初始化

因为引入了FN,咱们须要对整个集群的初始化进行调整,调整后的流程如下图所示。

初始化过程先是GTM,再到FN,最初是CN、DN。须要留神的是,咱们要保障FN启动后,本机上的CN、DN再启动,这是因为本机上的CN、DN启动后须要向本机的FN进行注册,只有注册胜利才可能对外提供服务。敞开程序恰好与启动程序相同,也就是说,敞开的时候先敞开DN、CN,再敞开FN,最初是GTM。

2

FN数据发送与接管过程

2.1 执行打算

咱们举一个例子。有两张表,一个是A表,一个是B表,它们都有两列,f1列作为散布列,f2不是散布列,咱们要进行一个join的查问:B表用的是f2,它不是一个散布列,这样的话就须要进行数据重散布,就产生了数据的交互。

后面提到FN是通过FID、原节点ID、目标节点ID进行数据路由,原节点ID、目标节点ID很分明不赘述,先重点理解FID。

FID在生成执行打算的时候曾经确定,整体执行打算如下:如右下角的方框所示,先对B表进行数据扫描,扫描完之后把数据重散布发送到其余机器节点上,其余机器节点收到这部分数据后进行一个join,join完结之后再进行投影。

扫描之后再发送进来这一部分,对应的FID是FID2;join后果发送数据这一部分,对应的是FID1;最初收到数据做投影的是FID0——只有牵扯到数据交互,就会有FID来进行标识。这个FID是GTM来进行统一分配治理,能够保障任意时刻都是全局惟一,这也就能标识”我是谁”这个逻辑。

2.2 数据传输

针对下面的执行打算,咱们来具体看一下数据的传输过程。在执行FID2的时候,DN1上的数据须要传输到DN2上,DN2上的数据也须要传输到DN1上。咱们先看DN1怎么到DN2这个链路。首先是FN1通过共享内存,拿到DN1上的数据后,发现要去的是DN2,而且当初执行的是fid2这个执行打算,它就把这部分数据通过fid2发送了进来。服务器3上的FN,就会在本人的fid2的接管队列中收到这部分数据,收到这部分数据后,再通过共享内存传递给这个服务器上的DN2,这样数据就传送过去了。同样的,DN2上的数据也是这样传送过来DN1的。在DN1和DN2实现数据传输后,须要把Join后果数据传送到CN下来做投影,此局部对应的是fid1,CN上的FN作为一个目标节点,它会从fid1的接管队列中收到来自于FN1、FN2的数据,而后通过共享内存传递到CN,CN再返回到客户端,这样就实现了整个数据传输的路由过程。

2.3 FN外部架构

下图是FN外部的具体架构。FN外部大略可分为四类:

元数据管理,治理与其余节点通信的所需的信息,比方节点ID、注册过程ID、FID应用状况等;
针对每个DN节点要进行数据传送的共享内存,个别共享内存中存储的是一些DN节点的统计信息、拥塞管制信息;
FN作为发送者,这里会有一些发送的共享内存、发送队列、发送线程;
FN作为接收者,会有一些接管的共享内存、接管线程和接管队列。

2.4 数据收发流程

模块是怎么相互合作来进行发送、接收数据的。

首先咱们来看一下数据发送过程。后面提到,CN/DN启动的时候须要向本机的FN进行注册,注册时FN就会为注册的节点调配好内存空间,放在buffer pool外面,留待当前备用。这样的话,当前注册节点的这些DProcess过程(就是真正去解决用户申请的过程)它调用接口向FN申请共享内存,如果要发送,就把本人那局部的数据放到申请的内存外面去,放完之后,将这部分数据放到发送端FN的Fragment的音讯队列里去,它就返回了。FN外部会有调度线程,会依据数据的FID从Fragment队列中读出来,看这个音讯要去的目标节点是哪里,把它调度到对应的目标节点的发送音讯队列外面去。FN外部有一个发送线程,发送线程就会真正地进行发送,发送完之后将那局部内存开释回buffer pool,这是整个发送过程。

接收端这边,收到数据也会向对应的buffer pool申请一块内存来寄存这部分数据。而后把这部分寄存接收数据的内存挂载到接管队列外面,接收端的FN也有本人的调度线程,会查看接管队列外面的音讯的FID,依据FID再把它调度到对应的Fragment队列里去。最初DN2端这边的DProcess生产过程(用于解决用户申请),它会从Fragment生产队列中把对应的数据读出来,读出来后把这块内存再开释回去,这样就实现了整个FN外部数据的收发流程。

3

企业级Oracle兼容能力解读

3.1 分区表能力

首先是最罕用的分区表能力。TDSQL-A反对range、list、hash、高性能等距离分区,并且能够反对多级分区级联,在分区表的拜访办法上,也全面兼容了oracle的语法,除了能够间接拜访子表外,还能够关联父表名字来进行拜访。还能够反对Update分区字段的值。

就像下图中的例子所示:0-30是一个子表,30-60是一个子表,咱们能够把这个表外面的id,即分区键,把它改成不属于它以前这个分区范畴内的数据,改了之后TDSQL-A外部会主动批改这条数据,将它由以前的分区挪到新的分区外面。以前的分区就查不到这条数据了。

除此之外,咱们还反对分区子表的合并拆分能力、新加分区时default分区主动挪动的能力。

咱们先来看分区子表的拆分与合并。随着工夫的推移,在应用过程中,零碎的分区会越来越多,为了方便管理,很多用户就会想将晚期的分区进行合并,TDSQL-A也像oracle一样提供了这样的能力。像图中右边所示,它能够通过merge partitions将1月份和2月份的分区进行合并,造成一个稍大的分区,这样就能够无效地去缩小分区的数量。

分区的拆分刚好与合并相同,对于用户常常拜访的热点数据,如果这些热点数据所处的分区内数据太多的话,每次就会扫到很多不必要的数据,咱们能够通过拆分,将热点的分区拆分掉,拆分之后,在后续进行热点拜访的时候,比如说我要拜访“50”这个数据,我就只扫描30-60的子分区,0-30的分区就不须要扫描,这就能无效缩小数据扫描,进步查问效率。

分区表个别会有默认的default分区,用来存储不属于其它分区的数据。在下图这个例子中,比如说2019年12月份的数据,还有2020年3月份的数据,它都不属于后面已创立的这两个子分区,但如果用户在之后创立了2020年3月份这个新分区的话,咱们数据库就会主动把这部分属于这个分区的数据从default这个默认分区,挪动到对应的分区里。之后default分区中就不蕴含这部分数据了,只有剩下的其余数据。这相似于oracle创立了分区之后default分区会主动挪动的性能。

3.2 数据治理能力

TDSQL-A反对不同子分区存储到不同的节点组,不同的节点组关联着不同机器,通过这样的计划能够将热数据存储在配置好的机器上,冷数据存储在略微差点的机器上,以此来实现冷热数据的分级存储,升高用户数据的存储老本。

3.3 存储过程能力

另一个重要的 Oracle兼容能力就是存储过程,TDSQL-A中也是反对的。比如说,存储过程中能够指定,在i是偶数的时候,对这个事物进行提交,它是奇数的时候,对它进行回滚。这样的话,最终执行实现之后,这个数据表中就只有偶数的数据。

3.4 函数扩大语法能力

此外,为了全面兼容oracle,TDSQL-A的函数在创立调用语法上也进行了适配。比如说创立的时候,能够不像PG那样指定用$$进行突围,能够做到像oracle一样以斜杠来进行结尾。如果有空参数的话,也能够不须要括号。

咱们还能够在任意statement前或者是block前去增加label,而后通过goto去跳转到指定label里去。如果是原生PG的话,个别只有循环后面能力增加label。这些都是属于TDSQL-A本人开发的新性能。

在函数下面,咱们还增加了对WITH FUNCTION的语法反对。比如说这个例子中SELECT调用的这个add_fnc函数,就只对这个SELECT有用,对于其余任何查问都是没有用的。而且如果这个WITH FUNCTION函数的函数名跟零碎中其余函数名重名的话,这个SELECT中的函数优先级是高于其余函数的。

3.5 PACKAGE反对

和存储函数相干的package,咱们也是反对的。通过创立这样的一些包,用户能够将一些罕用的函数分装到一个包里去,之后能够指定一个包来进行相应的调用。这里须要留神的是,创立的话,应该是先创立包再去创立一个包体,删除的话刚好是相同的。

3.6 ROWID & ROWNUM反对

很多用户常常应用的oracle中典型的ROWID和ROWNUM,TDSQL-A也是反对的。如果用户在建表的时候,指定了WITH ROWID这样的参数,这样建进去的表在前面进行查问时,就能够指定要查的这个ROWID,就能够看到它惟一标识了这一行的数据,并且在进行数据变更之后,依然能够保障这个ROWID不变。跟ROWID相近的还有ROWNUM,但实际上ROWNUM跟它有很大区别,它不是真正存储的,它只是用户在进行查问之后,对返回的记录进行编号。

3.7 MERGE INTO 语法反对

TDSQL-A还反对MERGE INTO语法。咱们增加了对MergeStmt子句的解析,也减少了MERGE命令,能够做到将两个表进行MERGE合并。像这个例子中所示,将MERGE INTO到test1里,应用参考test2,如果匹配上的话,就对test1的数据进行更新,如果不匹配,就能够通过这个语法,将 test2外面的数据全副增加到test1里去,达到合并的目标。、

3.8 Start with connect by反对

Oracle里的start with connect by档次查问,TDSQL-A也是反对的。它实际上是进行了树的中序遍历。咱们是通过一个递归CTE来进行实现的,最终实现档次查问的后果。

3.9 PIVOT & UNPIVOT反对

TDSQL-A还反对PIVOT和UNPIVOT函数。PIVOT是一个把行数据转成列属性的函数,UNPIVOT刚好相同,是将列属性转成行数据。大略的实现办法是:对于PIVOT,针对不在这个in中的这些列,把它转换为一个grop by外面的字段,来进行实现。对于UNPIVO,把这些数据转换成一个lateral join来进行实现。这些比拟有特点的Oracle罕用函数,TDSQ-A都是反对的。

3.10 其余兼容能力

此外咱们还反对Oracle中List AGG、SQL hints、同义词、Dual表、各种日期、工夫、字符串、表达式等罕用函数,能够做到Oracle罕用语法的90%以上兼容。