文章目录
简介
ShuffleClient
不仅是将shuffle文件上传到其他Executor或者下载远程Executor文件到本地的客户端,也是提供可以被其他Executor访问的shuffle服务。
Spark任务是分布式计算的,每个Task运行在不同的机器上。map任务执行完成后会将输出结果存储到任务执行所在的机器的本地存储中,并通过本地的
MapOutputTrackerWorker
向Driver
中DAGScheduler
里的MapOutputTrackerMaster
汇报。reduce任务很可能和map任务不在同一台机器上执行,reduce任务执行前首先会向本地MapOutputTrackerWorker
请求map任务输出结果(如果没有则其向Driver
中DAGScheduler
里的MapOutputTrackerMaster
获取)。得到地址后,reduce任务会通过ShuffleClient
远程下载map任务的中间输出。因此,ShuffleClient
是Spark计算框架中的一个重要组件。
UML类图
ShuffleClient
的UML类图如下:
创建过程
ShuffleClient
是在BlockManager中创建的,根据spark.shuffle.service.enabled
配置来决定是否启用外部服务作为shuffle服务,默认使用构造函数中传入的blockTransferService
:
// BlockManager.scala
private[spark] val externalShuffleServiceEnabled =
conf.getBoolean("spark.shuffle.service.enabled", false)
// 读取其他executor的shuffle文件的客户端。它或者是一个外部服务,或者仅仅是标准的BlockTransferService
// 直接地连接到其他executors。
private[spark] val shuffleClient = if (externalShuffleServiceEnabled) {
val transConf = SparkTransportConf.fromSparkConf(conf, "shuffle", numUsableCores)
new ExternalShuffleClient(transConf, securityManager, securityManager.isAuthenticationEnabled())
} else {
blockTransferService
}
BlockManager是在SparkEnv中创建的,并同时创建了blockTransferService
服务并将其传入BlockManager的构造函数中。blockTransferService
的实际实现类为NettyBlockTransferService
:Spark和Hadoop一样,都采用Netty作为shuffle服务。下面我们以默认的NettyBlockTransferService
为例进行介绍。
// SparkEnv.scala
val blockTransferService =
new NettyBlockTransferService(conf, securityManager, bindAddress, advertiseAddress,
blockManagerPort, numUsableCores)
val blockManagerMaster = new BlockManagerMaster(registerOrLookupEndpoint(
BlockManagerMaster.DRIVER_ENDPOINT_NAME,
new BlockManagerMasterEndpoint(rpcEnv, isLocal, conf, listenerBus)),
conf, isDriver)
// NB: blockManager is not valid until initialize() is called later.
val blockManager = new BlockManager(executorId, rpcEnv, blockManagerMaster,
serializerManager, conf, memoryManager, mapOutputTracker, shuffleManager,
blockTransferService, securityManager, numUsableCores
实现
ShuffleClient接口定义
首先看下ShuffleClient接口类的定义如下。ShuffleClient定义了从executor或者外部服务读取shuffle文件数据的接口。
/** 提供了一个从executor或者外部服务读取shuffle文件的接口。 */
public abstract class ShuffleClient implements Closeable {
/**
* 初始化ShuffleClient,指定当前executor的appId。
* 必须在ShuffleClient其他方法调用前被调用。
*/
public void init(String appId) { }
/**
* 从远程节点异步获取一组blocks
*
* 注意:该API接口接收数组参数,所以可以实现批量请求。另外,该方法没有返回一个future对象,所以子类
* 实现可以在一个block获取成功后立即回调onBlockFetchSuccess,而不是等待所有的blocks都获取成功。
*/
public abstract void fetchBlocks(
String host,
int port,
String execId,
String[] blockIds,
BlockFetchingListener listener,
Te