Doris 不同Plan Fragment之间的数据扭转

关键对象

  • VExchangeNode:负责不同fragment的数据接收的node。
  • DataSink:负责不同fragment的数据发送的node(这是个基类)。
  • VDataStreamRecvr:在VExchangeNode中真正的负责数据的接收。
  • VDataStreamSender:在DataSink中真正的负责数据的发送,如果支持向量化则会new VDataStreamSender,否则是new DataStreamSender

如果两个需要传递数据的Plan Fragment在同一个BE节点上,那么上层的sender会直接通过RuntimeState对象进而找到recver,直接在sink节点调用exchange node 中的recver对象的add_block将数据直接放入exchange node 中。【如何放,是否涉及内存拷贝】

sink如何发送数据 && exchange node如何接收并合并

  1. sink如何发送数据给exchange node
    1) 发送给localexchange node
    这里就直接调用recvradd_block方法,直接将数据放入VDataStreamRecvr::_sender_queues::_block_queue中,
    2) 通过rpc发送给 remoteexchange node
    最终是将数据通过rpc,同local一样放入了_block_queue中,后续上层节点调用get_next方法时会调用_sender_queuesget batch方法从_block_queue中获取数据
    调用链:
    VDataStreamSender::Channel::send_block -> PInternalServiceImpl::transmit_block -> VDataStreamMgr::transmit_block -> VDataStreamRecvr::add_block -> VDataStreamRecvr::SenderQueue::add_block
  2. exchange node如何接收、存储数据
    exchange node在真实运行时,上层算子会调用exchange nodeget next方法,传入一个空block,通过exchange nodeget next方法将数据通过block返回给上层算子。
    1) 单个sender发来的数据
    调用_sender_queuesget_batch方法将数据从_block_queue中取出,最终返回给get_next方法的block。
    2) 多个sender发来的数据
    每个remote sender都会将数据通过rpc发送给exchange node,首先会到达exchange node所在bePInternalServiceImpl::transmit_block方法,进而调用VDataStreamMgr::transmit_block方法中,该方法中会根据node_id找到对应需要接收数据的exchange node中的recvr,然后recvr负责接收数据,并根据sender_id, 将数据通过add_block方法存入指定的_sender_queues_block_queue中。

如何合并的多个数据源的数据呢?
Status VSortedRunMerger::get_next 看这里

简而言之,sink向exchange node发送数据共分为2种情况:

  • 两个节点在同一个BE,local send ,这样sender直接调用recvradd block,将数据直接放入recvr中的指定位置
  • 两个节点不在同一个BE,则通过rpc send,在exchange node所在be节点上找到exchange noderecvr,调用add block将数据放入指定位置

上面一直在说把数据放入指定位置,这个指定位置指的是哪里呢?这里也可以分为2种情况:
前置信息:recvr中有一个_sender_queues对象,用于接收(add block)、存放(_block_queue)sink节点发送来的数据。

  • exchange node只有一个数据源:_sender_queues中只有一个SenderQueue对象,直接用_sender_queues[0]->add_block接收数据并保存到_sender_queues[0]->_block_queue中。上层节点通过get next获取数据时则会直接从_block_queue中将数据取出,并通过入参将数据返回上层。
  • exchange node有多个数据源:这里可以分为两个阶段,接收数据阶段与合并阶段。(1)接收数据阶段:_sender_queues中有多个SenderQueue对象,VDataStreamRecvr::add_block中会根据sink节点发送数据时携带的信息sender_id使用_sender_queues[sender_id]->add_block将数据放入到指定SenderQueue_block_queue中(即:_sender_queues[sender_id]->_block_queue)。(2)数据合并阶段:上层节点通过get next获取数据时则会调用_merger->get_next方法将数据合并后通过入参将数据返回给上层。

exchange node中负责接收数据的recvr如何创建?

在plan fragment executor的prepare方法中会调用内部算子的prepare方法,如过plan fragment由agg node + exchange node组成,则会调用agg node的prepare方法,进而通过ExecNode::prepare()方法调用其child的prepare方法,即exchange node的prepare方法,此时exchange node的recvr创建完毕,等待接收数据。

数据如何从exchange node中传输给同fragment内上层算子

在plan fragment 在执行过程中,会顶层的算子(root节点_plan)会一直调用get next方法从其子节点获取数据,如果不包含scan算子,那么最底层节点会是exchange node,也就是说上层算子是通过get next方法从exchange node获取数据,exchange node这里的流程为:

这里以单一数据源不需要合并为例
exchange_node::get_next -> recvr::get_next -> SendQueue::get_batch
这里通过SendQueue::get_batch方法,将sink节点发送放入_block_queue中的数据返回给入参Block,即完成数据的返回
在 SendQueue::get_batch 时,数据有可能还未发送到_block_queue中,这里是在SendQueue::get_batch方法中while
循环+条件变量的形式等待数据的到来。

Exchange node的创建

exchange node的创建方式,所需的参数同scan agg算子相同,都是在ExecNode::create_node 方法中进行创建的,入参为ObjectPool,TPlanNode,DescriptorTbl

  • ObjectPool是用于管理new出来的对象
  • TPlanNode是比较重要的,从中取出所需参数,然后创建Exchange node
  • DescriptorTbl,这个具体还没理解透彻。。。但是这个对象和scan agg算子传下来的是相同的。

TPlanNode中比较重要的数据结构是TExchangeNode,这里包含了创建TExchangeNode的所需对象。
这个对象的创建是在FE中,fe/fe-core/src/main/java/org/apache/doris/planner/ExchangeNode.java的toThrift()方法中进行赋值的。

struct TExchangeNode {
  // The ExchangeNode's input rows form a prefix of the output rows it produces;
  // this describes the composition of that prefix
  1: required list<Types.TTupleId> input_row_tuples
  // For a merging exchange, the sort information.
  // 当Exchange node需要接收多个sink节点发送来的数据时,需要使用该对象
  2: optional TSortInfo sort_info
  // This is tHe number of rows to skip before returning results
  3: optional i64 offset
}

未完 待续。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值