1. 引言:
本文讨论在presto中,数据在上下游加工传递的时候,到时是下游主动向上游拉数据,还是上游主动向下游推数据的问题。下述会分成split与split之间传递,task与task之间传递,stage与stage之间传递分开讨论。
2. split <--> split
在presto之间,split之间传递数据不需要经过网络,是在同一个进程内进行,因此presto将数据传递的方式设计为上游的split直接通过下游split的addInput接口推给下游。代码在Driver::processInternal中:
private ListenableFuture<?> processInternal(OperationTimer operationTimer)
{
...
// if we got an output page, add it to the next operator
if (page != null && page.getPositionCount() != 0) {
next.addInput(page);
next.getOperatorContext().recordAddInput(operationTimer, page);
movedPage = true;
}
...
}
3. Task <--> Task
在Presto 之中,Task与Task之间数据的传递是通过下游的Task主动向上游的Task定期拉数据实现的,代码入口在SqlStageExecution::addExchangeLocations:
for (RemoteTask task : getAllTasks()) {
ImmutableMultimap.Builder<PlanNodeId, Split> newSplits = ImmutableMultimap.builder();
for (RemoteTask sourceTask : sourceTasks) {
URI exchangeLocation = sourceTask.getTaskStatus().getSelf();
newSplits.put(remoteSource.getId(), createRemoteSplitFor(task.getTaskId(), exchangeLocation));
}
在往每个Task添加split的时候,split都保存着上游task的地址exchangeLocation
task.addSplits(newSplits.build());
}
下游的task的split中保存着上游source task的地址,在后续的计算过程中不断调用HttpPageBufferClient的sendGetResults到上游取数据回来处理。自己处理完的数据则是放置在outputBuffer中,等下游的task过来取。
4. stage <--> stage
stage 之间的数据交换其实是同过一个Exchange的task进行的,每个stage的入口处便是一个ExchangeOperator,因此也是下游的加工者主动向上游的加工者拉取数据的方式。