1、 Presto中的task
在Presto中,coordinator对worker的任务分发和调度是以task的形式进行的。一个分布式计划的Stage包含1个或者多个Task,每个Task包含1个或者多个Split。了解Presto中的Task管理机制有助于了解Presto中的Coordinator与Worker之间的调度机制。
在Presto中,每个task有单独的ID,TasK ID的构成格式为queryID.stageID.Task顺序号,比如:比如:20211103_225744_00000_wqant.0.0
可以在原生页面中查看Tasks的状态:
2. Task的生成
Presto中生成Task的代码在:
SqlStageExecution::scheduleSplits
task = scheduleTask(node, taskId, splits, OptionalInt.empty());
RemoteTask task = remoteTaskFactory.createRemoteTask
3. coordinator向worker提交task
coordinator向worker提交tasks的代码流程:
RemoteTask task = remoteTaskFactory.createRemoteTask
new HttpRemoteTask(..., PlanFragment, ...)
locationFactory.createTaskLocation(node, taskId)
TaskInfo initialTask = createInitialTask(..., location, ...)
TaskStatus.self = self //self就存放着task提交的地址,比如:http://workerip:workerport/v1/task/20211103_225744_00000_wqant.0.0
executor.execute(this::sendUpdate);
HttpUriBuilder uriBuilder = getHttpUriBuilder(taskStatus);
uriBuilderFrom(taskStatus.getSelf());
httpClient.executeAsync(request, ....) //至此,coordinator将Task请求提交给worker执行
4. worker 执行Task
@POST
@Path("{taskId}")
TaskResource::createOrUpdateTask
taskManager.updateTask
sqlTask.updateTask
sqlTaskExecutionFactory.create
createSqlTaskExecution(..., localExecutionPlan, ...)
createTaskHandle(taskExecutor)
taskExecutor.addTask
TaskExecutor::addRunnerThread
executor.execute
split.process(); // 至此进行了split的数据处理
5. Task执行结果拉取
在构建Task的时候,下游的Task保存着上游的Task的result url, 下游任务开始的时候,实时地从上游的获取结果的url拉取数据,上游产生一批数据,下游便拉过来处理,实现了pipeline式的作业调度,避免一个task必须等另外一个task完成才能处理数据的空等待,这也是Presto能高效进行数据处理和计算一大原因。
SqlQueryScheduler::createStages
stage::addExchangeLocations
URI exchangeLocation = sourceTask.getTaskStatus().getSelf(); //self 就是3提到的task的提交地址
newSplits.put(remoteSource.getId(), createRemoteSplitFor(task.getTaskId(), exchangeLocation)); //将下游split的source url 设置为上游的result url
uriBuilderFrom(taskLocation).appendPath("results") //self + results就是上游task结果存放的url