Hive on Spark源码分析(一)—— SparkTask
Hive on Spark源码分析(二)—— SparkSession与HiveSparkClient
Hive on Spark源码分析(三)—— SparkClilent与SparkClientImpl(上)
Hive on Spark源码分析(四)—— SparkClilent与SparkClientImpl(下)
Hive on Spark源码分析(五)—— RemoteDriver
Hive on Spark源码分析(六)—— RemoteSparkJobMonitor与JobHandle
之所以首先分析SparkTask的源码的原因,是根据Hive on Spark的运行模式和任务提交流程的出来的。首先我们看一下Hive on Spark运行模式:
Hive on Spark(HOS)目前支持两种运行模式:本地(local)和远程(remote)。当用户把Spark Master URL设置为local时,采用本地模式;其余情况则采用远程模式。本地模式下,SparkContext与客户端运行在同一个JVM中;远程模式下,SparkContext运行在一个独立的JVM中。本地模式通常仅用于调试。因此我们主要分析一下远程模式(Remote SparkContext,RSC)。下图展示了RSC的工作原理。
用户的每个Session会创建一个SparkClient,SparkClient会启动RemoteDriver进程,并由RemoteDriver创建SparkContext。SparkTask执行时,通过Session提交任务,任务的主体就是相应的SparkWork。SparkClient将任务提交给RemoteDriver,并返回一个SparkJobRef,通过该SparkJobRef,客户端可以监控任务执行进度,进行错误处理,以及采集统计信息等。由于最终的RDD计算没有返回结果,因此客户端只需要监控执行进度而不需要处理返回值。RemoteDriver通过SparkListener收集任务级别的统计数据,通过Accumulator收集Operator级别的统计数据(Accumulator被包装为SparkCounter),并在任务结束时返回给SparkClient。
SparkClient与RemoteDriver之间通过基于Netty的RPC进行通信。除了提交任务,SparkClient还提供了诸如添加Jar包、获取集群信息等接口。如果客户端需要使用更一般的SparkContext的功能,可以自定义一个任务并通过SparkClient发送到RemoteDriver上执行。
因此在接下里的几篇文章里,我将会针对上面提到的Session、SparkClient、RemoteDriver,以及与job监控相关的JobMonitor进行分析,并且主要针对远程模式的相关实现类。
@Override
public int execute(DriverContext driverContext) {
//返回码初始为0
int rc = 0;
//创建session,以及用来管理多个session的sessionManager
SparkSession sparkSession = null;
SparkSessionManager sparkSessionManager = null;
try {
//打印一些提示能够控制sparkWork的reducer数目的参数的信息
printConfigInfo();
sparkSessionManager = SparkSessionManagerImpl.getInstance();
sparkSession = SparkUtilities.getSparkSession(conf, sparkSessionManager);
public RpcServer(Map<String, String> mapConf) throws IOException, InterruptedException {
this.config = new RpcConfiguration(mapConf);
this.group = new NioEventLoopGroup(
this.config.getRpcThreadCount(),
new ThreadFactoryBuilder()
.setNameFormat("RPC-Handler-%d")
.setDaemon(true)
.build());
this.channel = new ServerBootstrap()
.group(group)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
SaslServerHandler saslHandler = new SaslServerHandler(config);
final Rpc newRpc = Rpc.createServer(saslHandler, config, ch, group);
saslHandler.rpc = newRpc;
Runnable cancelTask = new Runnable() {
@Override
public void run() {
LOG.warn("Timed out waiting for hello from client.");
newRpc.close();
}
};
saslHandler.cancelTask = group.schedule(cancelTask,
RpcServer.this.config.getServerConnectTimeoutMs(),
TimeUnit.MILLISECONDS);
}
})
.option(ChannelOption.SO_BACKLOG, 1)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.bind(0)
.sync()
.channel();
this.port = ((InetSocketAddress) channel.localAddress()).getPort();
this.pendingClients = Maps.newConcurrentMap();
this.address = this.config.getServerAddress();
}
SparkWork sparkWork = getWork();
sparkWork.setRequiredCounterPrefix(getOperatorCounters());
perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.SPARK_SUBMIT_JOB);
SparkJobRef jobRef = sparkSession.submit(driverContext, sparkWork);
rc = jobRef.monitorJob();
SparkJobStatus sparkJobStatus = jobRef.getSparkJobStatus();
if (rc == 0) {
SparkStatistics sparkStatistics = sparkJobStatus.getSparkStatistics();
if (LOG.isInfoEnabled() && sparkStatistics != null) {
LOG.info(String.format("=====Spark Job[%s] statistics=====", jobRef.getJobId()));
logSparkStatistic(sparkStatistics);
}
LOG.info("Execution completed successfully");
} else if (rc == 2) {
jobRef.cancelJob();
}
sparkJobStatus.cleanup();
} catch (Exception e) {
String msg = "Failed to execute spark task, with exception \'" + Utilities.getNameMessage(e) + "\'";
// Has to use full name to make sure it does not conflict with
// org.apache.commons.lang.StringUtils
console.printError(msg, "\\n" + org.apache.hadoop.util.StringUtils.stringifyException(e));
LOG.error(msg, e);
rc = 1;
} finally {
Utilities.clearWork(conf);
if (sparkSession != null && sparkSessionManager != null) {
rc = close(rc);
try {
sparkSessionManager.returnSession(sparkSession);
} catch (HiveException ex) {
LOG.error("Failed to return the session to SessionManager", ex);
}
}
}
return rc;
}