MPPDB通信库发展历程1.Postgres-XC方法采用libpq通信库实现CN和DN之间的连接CN负责计算DN仅进行数据存储。缺点随着计算任务的不断增大CN计算出现瓶颈且白白浪费DN的计算能力。2.V1R3方法提出分布式执行框架将计算下推到DN上执行DN不仅作为存储同时承担计算任务。由于每个DN只存储有一部分数据因此DN间也需要进行通信采用stream线程TCP直连每个连接都需要一个TCP端口。缺点随着集群规模的增加DN之间的连接数不断增加在大并发场景下需要大量的TCP端口而实际情况是由于单机TCP端口只有65535个TCP端口数严重限制了数据库的集群规模和并发规模。3.V1R5-V1R7C00方法结合SCTP协议的多流优点DN间的通信采用SCTP通信库架构使用逻辑连接来代替物理连接用来解决DN之间连接太多的问题。缺点SCTP协议本身存在的内核BUG通信报错。4.V1R7C10方法TCP代理通信库。缺点CN和DN之间的物理连接数也会暴涨。5.V1R8C00方法CN和DN之间也采用逻辑连接实现即CN多流。问题1DN间是查询结果的通信还是原始数据的通信解既有查询结果也有原始数据DN之间的数据交流是Hash之后各个DN根据所需获取。通信模型的设计1. Pooler通信模型问题2连接池上的CN、DN是否存在交集即poolA中的DN在poolB中也存在解不存在。问题3CN和CN的连接是做什么的为什么设计连接池连接CN上的PG线程CN上为什么有多个PG线程有什么用途解CN和CN之间连接是为了数据同步等包括建表之后的信息交汇。CN上的PG线程也是为了用户查询建立。问题4DN上为什么有多个PG线程有什么用途解一个查询操作就是创建一个新的PG线程。问题5如何理解gsql客户端退出时只退出PG线程和agent代理线程而取到的slot连接会还回database pool解slot连接退回到pooler下次连接可以直接获取若不存在则重新创建。问题6DN间的TCP连接数C (H * D * Q * S* D为什么最后乘以D而不是(D - 1/ 2 ? 此外这个公式是否存在高重复每次查询都要建立DN间的通信而不考虑重复性DN间的通信线程数量是否有限制解数据是双向通信但执行算子是单向的所以不能除以2。数量有限制但可以调整。2. DN间stream线程通信模型执行计划需要使用多个线程进行执行包括1个CN线程和每个DN上3个线程t1-t3。每个DN节点都有3个线程是因为数据是分布到每个DN上的在执行查询过程中查询的每个阶段每个DN都要参与。自下而上是数据流自上而下是控制流。具体执行过程如下每个DN的t3顺序扫描table表将表数据广播到所有DN的t2线程;每个DN的t2接收t3的数据建立hash表然后扫描store_sales数据与customer表进行hashjoinjoin结果进行哈希聚集后重分布发送到对应DN的t1线程;每个DN的t1线程将收到的数据进行第二次哈希聚集 排序后将结果传输到CN;CN收集所有DN的返回数据作为结果集返回。问题7DN上是否执行查询操作DN广播的数据是否属于同一个数据表每个DN都广播数据那最后所有DN的数据是否相同图中t2发送给所有DN的t1、解执行DN上存的数据是表的几分之几不是整个表也不是一个表的部分是所有表的一部分这样做是为了并发。DN数据不相同因为各取所需。SCTP通信库设计1. 概要SCTP 协议一种可靠、保序协议支持message-based模式单个通道支持65535个流且多流之间互不阻塞利用该特性可以打破设备物理连接数对大规模集群节点间通信的限制支持更大规模的节点规模。通道共享每两个节点之间有一个数据传输单向SCTP物理通道,在这条物理通道内部有很多逻辑通道inner Stream每个stream流由producer发送到consumer利用SCTP内部支持多流的特性不同的producer consumer对使用通道中不同的流(SCTP流)因此每两个点之间仅需要两个数据连接通道。通道复用查询完成后物理通道中的逻辑连接关闭物理连接不关闭后面的查询继续使用建好的物理连接。流量控制采用pull模式因为SCTP通道的所有流共享内核的socket buffer, 为了避免一个连接发的数据量过大,consumer端却不接收导致kernel的buffer被填满,阻塞了其他流的发送,增加了流控,给每个流设置一个quota, 由接收端分配当有quota时告知发送端可发送数据发送端根据发来的quota值发送quota大小的数据量实现接收端与发送端同步控制为了保证控制信息的可靠性将控制信息和数据通道分离流控信息走单独的一条双向TCP控制通道。2. 架构TCP ChannelsTCP控制通道控制流走此通道SCTP ChannelsSCTP数据通道包含很多stream流数据流走此通道Send Controller发送端流控线程gs_senders_flow_controller()收发控制消息Recv Controller接收端流控线程gs_receivers_flow_controller()接收端用于发送和接收控制报文与代理接收线程不同代理接收线程接收的是数据而接收流控线程接收的是报文Receiver代理接收线程gs_receivers_loop()用于接收数据的线程从sctp数据通道中接收数据将数据放到不同逻辑连接的不同cmailbox报箱中并通知执行层的consumer工作线程来取取走后有空闲的buffer时接收端流控线程会通过tcp控制通道通知发送端还有多少空闲内存即还有多少quota可用于继续接收数据Auxiliary辅助线程gs_auxiliary()由top consumer每个两秒检查一下处理公共事务如DFX消息Cancel信号响应等数据PULL模型每个逻辑连接有quota大小的buffer需要数据时将空闲buffer的大小即quota发送给发送端发送端即可以发送quota大小的数据quota不足时阻塞发送直到接收端的buffer被应用取走。TCP多流实现TCP代理在现有的逻辑连接、代理分发、quota流控等实现的基础上将数据通道从SCTP协议替换成TCP协议TCP代理逻辑连接的实现基于headdata的数据包收发模型在head中写入逻辑连接id及后续data的长度。问题8单机TCP只有65535个端口SCTP呢TCP多流和TCP在端口上的区别TCP的三次握手是否依旧SCTP是基于消息流传输数据收发的最小单位是消息包chunk一个SCTP连接Association同时可以支持多个流stream每个流包含一系列用户所需的消息数据chunk。而TCP协议本身只能支持一个流因此我们需要在这一个流中区分不同逻辑连接的数据通过在TCP报文的head中写入逻辑连接id及后续data的长度来区分这样虽然TCP只有一个数据包组成但每个数据包包含多个块实现了TCP的多流。同时发送时需保证整包原子发送。问题9如何多流是多个通道同时发送headdata吗解一个流发送完整的数据。多流是并发。TCP代理通信库的发送端实现producerA和producerB分别给DN1发送数据为保证发送端headdata发送的完整性producerA首先需要对单个物理连加锁此时producerB处于等锁状态producerA将数据完整发送到本地协议栈后返回并释放锁producerB获得锁后发送数据。节点数越多冲突越少。问题10加锁等待是否影响效率SCTP的实现也是如此解不影响因为有缓存buffer。问题11数据丢失永远无法达到head怎么办一直缓存解不会丢失TCP协议有保证。CN多流实现在V1R8C00版本中CN和DN之间的链接使用libcomm通信库即两个节点间仅存在一条物理通道在该物理通道上使用逻辑连接通道实现并行通信。1.CN端流程建立连接CN调用Libcomm的gs_connect与DN建立连接入参中指明建立双向逻辑通道使用相同的nidxsidx同时初始化发送和接受的mailbox通过发送流控线程通知接收端;等待DN返回结果通过判断发送mailbox的状态确认DN端已成功建立的逻辑连接发送流控线程收到DN端的CTRL_READY报文;发送startuppacket通过PQbuildPGconn初始化libpq的pg_conn结构体生成startuppacket随后通过gs_send发送startuppacket给DN端;等待DN PG线程初始化通过LIBCOMMgetResult等待DN端返回ready for query报文之后认为连接建立成功。2.DN端流程初始化发送、接收mailboxDN端接收流控线程识别到连接请求来自CN后调用gs_build_reply_conntion注册CN的信息初始化发送mailbox随后初始化接收mailbox最终通过流控线程返回CTRL_READY报文表示逻辑通道建立成功;创建unix domain sockDN端接收流控线程创建一个unix domain sock将生成的逻辑连接地址通过该通道发给postmaster主线程;fork postgres子线程postmaster主线程的serverloop监听到unix domain sock后接收逻辑连接地址保存到port结构体中随后fork postgres子线程沿用原有逻辑;postgres线程初始化完毕在pg线程完成初始化后首先给CN回复ready for query报文随后进入ReadCommand函数等待CN发来的下一个Query。