文章目录
向Presto集群提交的所有查询最终都会转化成为一个个单独的Task在每个Worker节点上执行。每个task的作用就是处理一个或者多个Split,然后将处理的结果输送给下游Stage中的task。
一、创建Task
创建Task主要是调用HttpRemoteTask类的构造方法创建一个对象,并调用其start方法,而start方法最终又会调用封装在HttpRemoteTask内部的httpClient,向特定的Worker Node上的TaskResource服务发起RESTful请求,从而在特定的Worker Node上启动一个对应的SqlTaskExecution进行数据处理和计算。因此创建Task分为两部分:
Client端
在Client端创建Task的过程分为两步:创建HttpRemoteTask对象和调用该对象的start方法。启动Task的主要代码都集中在方法sendUpdate中。
// HttpRemoteTask.java
private synchronized void sendUpdate()
{
TaskStatus taskStatus = getTaskStatus();
// 将当前Task需要处理的所有Split都封装成TaskSource列表
List<TaskSource> sources = getSources();
// 将执行计划序列化以通过http发送给worker节点
Optional<byte[]> fragment = sendPlan.get() ? Optional.of(planFragment.toBytes(planFragmentCodec)) : Optional.empty();
Optional<TableWriteInfo> writeInfo = sendPlan.get() ? Optional.of(tableWriteInfo) : Optional.empty();
// 使用TaskSource列表、outputBuffers创建request请求
TaskUpdateRequest updateRequest = new TaskUpdateRequest(
session.toSessionRepresentation(),
session.getIdentity().getExtraCredentials(),
fragment,
sources,
outputBuffers.get(),
writeInfo);
byte[] taskUpdateRequestJson = taskUpdateRequestCodec.toBytes(updateRequest);
// 生成一个Post请求
HttpUriBuilder uriBuilder = getHttpUriBuilder(taskStatus);
Request request = setContentTypeHeaders(isBinaryTransportEnabled, preparePost())
.setUri(uriBuilder.build())
.setBodyGenerator(createStaticBodyGenerator(taskUpdateRequestJson))
.build();
ResponseHandler responseHandler;
if (isBinaryTransportEnabled) {
responseHandler = createFullSmileResponseHandler((SmileCodec<TaskInfo>) taskInfoCodec);
}
else {
responseHandler = createAdaptingJsonResponseHandler(unwrapJsonCodec(taskInfoCodec));
}
updateErrorTracker.startRequest();
ListenableFuture<BaseResponse<TaskInfo>> future = httpClient.executeAsync(request, responseHandler);
currentRequest = future;
Futures.addCallback(
future,
new SimpleHttpResponseHandler<>(new UpdateResponseHandler(sources), request.getUri(), stats.getHttpResponseStats(), REMOTE_TASK_ERROR),
executor);
}
需要将当前Task处理的数据都封装成TaskSource的列表,其中一个TaskSource代表一个Task处理的数据源,而Task处理的数据源又分为两类:Stage的输出和直接的数据源。对于Stage输出类型的数据源,TaskSource类封装了一个Stage的PlannodeId和根据该Stage上的TaskLocation生成的ScheduledSplit列表;对于直接的数据源,TaskSource类封装了一个数据源的PlannodeId和根据该数据源上的所有数据分片生成的ScheduledSplit列表。方法getSources会将两种数据源都封装成TaskSource,然后合并到一起。
Resource端
Coordinator向特定的Worker节点发送请求以启动一个SqlTaskExecution对象,用于执行Task计算任务,请求的处理均由类TaskResource完成。
// TaskResource.java
@POST
@Path("{taskId}")
@Consumes({APPLICATION_JSON, APPLICATION_JACKSON_SMILE})
@Produces({APPLICATION_JSON, APPLICATION_JACKSON_SMILE})
public Response createOrUpdateTask(@PathParam("taskId") TaskId taskId, TaskUpdateRequest taskUpdateRequest, @Context UriInfo uriInfo)
{
Session session = taskUpdateRequest.getSession().toSession(sessionPropertyManager, taskUpdateRequest.getExtraCredentials());
TaskInfo taskInfo = taskManager.updateTask(session,
taskId,
taskUpdateRequest.getFragment().map(planFragmentCodec::fromBytes),
taskUpdateRequest.getSources(),
taskUpdateRequest.getOutputIds(),
taskUpdateRequest.getTableWriteInfo());
if (shouldSummarize(uriInfo)) {
taskInfo = taskInfo.summarize();
}
return Response.ok().entity(taskInfo).build();
}
对新建Task的RESTful的处理主要是由方法taskManager.updateTask来完成的,其实就是