GPDB-内核原理-如何指定发送数据目的地
GPDB是一个分布式数据库,数据存放在各个segment上。Master用于接收用户请求,并将执行计划发送到各个segment上去执行。各个segment将数据发送个master汇总并返回用户。当进行join,join条件不是分布键时,各个segment就需要将数据重分布或者广播给其他segment。这个数据发送时,默认利用UDP协议进行传输,那么各个segment的端口号怎么指定呢?是否是各个segment配置的端口?发送时怎么指定发送目的?
1、发送函数
当然是motion算子来完成数据的传输,所以需要从motion算子执行开始入手看它的执行流程。
1)Motion算子执行时分为接收和发送两个模块。这里我们仅关注发送模块,由函数execMotionSender函数来完成。
2)execMotionSender会循环从执行计划子节点拉取数据,然后调用SendTuple函数将其发送走,直至所有数据都处理完。
1)SendTuple会先将记录序列化,放到发送缓冲中,若发送缓冲没了空间,则将其先放到链表tcItem中
2)然后将发送缓冲的东西发送走,再将链表内容拷贝过来,接着发送
3)发送函数由SendChunkUDPIFC函数完成
1)SendChunkUDPIFC函数最终调用sendto函数来发送
2)系统函数sendto的dest_addr入参为发送目的:指向目的套接字的地址
3)向上回溯,dest_addr为conn->peer,即MotionConn::peer
2、发送目的套接字
1)QE执行器开始执行的函数是standard_ExecutorStart函数
2)QE执行器开始执行时,会初始化UDP传输需要的连接等信息
3)流程中,可以看到conn->peer来自cdbProc->listenerAddr(IP或主机名)和cdbProc->listenerPort(端口)构建套接字内容
4)而cdbProc则来自recvSlice->primaryProcesses链表
那就需要看下该链表来自哪里。
3、Slice的primaryProcesses链表
1)QD:分发执行计划时,根据motion切分slice,并创建gang,即生成QE进程
2)可以看到primaryProcesses链表由CdbProcess* process构建组成
3)process中的端口listenerPort来自segdbDesc->motionListener
此时就需要继续溯源,看下segdbDesc->motionListener来自哪里?
4、Gang的创建cdbgang_createGang_async
创建gang,和QE建立好连接后,QE进程会将QE的监听端口发给QD,从而让QD将QE的UDP监听端口保存到segdbDesc->motioListener中。
QE的监听端口由Gp_listener_port保存,接着这个现索进行分析,看下Gp_listener_port来自哪里?
5、Gp_listener_port
Gp_listener_port的端口可以从上述流程看分析出:他是随机分配的端口。
每个segment上可能有不同的QE,此时不同QE分配的接收数据监听端口不同,那么就可以发送时指定到底发给哪个QE了。
不要以为同一个segment上的不同QEs它的接收数据监听端口相同,而发送数据时指定端口时不知道给同一个segment的哪个QE发送数据!
6、InitMotionLayerIPC什么时候调用
当然,还是QE进程fork出来初始化的时候,可以看到他是先随机分配监听端口,然后再将监听端口发送给QD的。