1.简介:SparkContext是Spark的驱动器,SparkEnv是Spark的环境,这是创建驱动器环境的过程(其它的还有执行器环境),说的是创建驱动器环境的关键方法。
2.相关方法:
SparkContext.scala文件:
创建的开始:
//在SparkContext初始化中,源码第434行。调用createSparkEnv方法创建
//_conf:配置,isLocal:Boolean是否为本地模式,listenerBus:监听器队列
_env = createSparkEnv(_conf, isLocal, listenerBus)
createSparkEnv方法:
private[spark] def createSparkEnv(
conf: SparkConf,
isLocal: Boolean,
listenerBus: LiveListenerBus): SparkEnv = {
//调用到SparkEnv中createDriverEnv方法
SparkEnv.createDriverEnv(conf, isLocal, listenerBus,
//驱动器核心的数量
SparkContext.numDriverCores(master, conf))
}
SparkEnv.scala文件:
createDriverEnv方法:
private[spark] def createDriverEnv(
conf: SparkConf,
isLocal: Boolean,
listenerBus: LiveListenerBus, //监听器队列
numCores: Int, //驱动器核心数
mockOutputCommitCoordinator: Option[OutputCommitCoordinator] = None): SparkEnv = {
assert(conf.contains(DRIVER_HOST_ADDRESS), //断言配置存在驱动器主机地址
s"${DRIVER_HOST_ADDRESS.key} is not set on the driver!")
assert(conf.contains(DRIVER_PORT), s"${DRIVER_PORT.key} is not set on the driver!")
val bindAddress = conf.get(DRIVER_BIND_ADDRESS) //驱动器绑定地址
val advertiseAddress = conf.get(DRIVER_HOST_ADDRESS) //驱动器主机地址
val port = conf.get(DRIVER_PORT) //驱动器端口
//如果有配置,创建io加密密匙
val ioEncryptionKey = if (conf.get(IO_ENCRYPTION_ENABLED)) {
Some(CryptoStreamUtils.createKey(conf))
} else {
None
}
create( //调用create方法
conf,
SparkContext.DRIVER_IDENTIFIER, //驱动器证书
bindAddress,
advertiseAddress,
Option(port),
isLocal,
numCores,
ioEncryptionKey,
listenerBus = listenerBus,
mockOutputCommitCoordinator = mockOutputCommitCoordinator
)
}
create方法:
//方法为驱动程序或执行程序创建SparkEnv
private def create(
conf: SparkConf,
//证书
executorId: String,
//绑定地址
bindAddress: String,
//主机地址
advertiseAddress: String,
//端口
port: Option[Int],
isLocal: Boolean,
//使用核心数
numUsableCores: Int,
//io加密密匙
ioEncryptionKey: Option[Array[Byte]],
//监听器队列
listenerBus: LiveListenerBus = null,
mockOutputCommitCoordinator: Option[OutputCommitCoordinator] = None): SparkEnv = {
//是否为驱动器
val isDriver = executorId == SparkContext.DRIVER_IDENTIFIER
//驱动器监听器总线不能为空
if (isDriver) {
assert(listenerBus != null,
"Attempted to create driver SparkEnv with null listener bus!")
}
//认证密码文件配置,是驱动器还是执行器
val authSecretFileConf = if (isDriver) AUTH_SECRET_FILE_DRIVER
else AUTH_SECRET_FILE_EXECUTOR
//安全管理器
val securityManager = new SecurityManager(conf, ioEncryptionKey, authSecretFileConf)
if (isDriver) {
//初始化身份验证密码
securityManager.initializeAuth()
}
ioEncryptionKey.foreach { _ =>
if (!securityManager.isEncryptionEnabled()) {
logWarning("I/O encryption enabled without RPC encryption: keys will be visible
on the " +"wire.")
}
}
//sparkDriver还是sparkExecutor
val systemName = if (isDriver) driverSystemName else executorSystemName
//远程通信环境
val rpcEnv = RpcEnv.create(systemName, bindAddress, advertiseAddress,
port.getOrElse(-1), conf,securityManager, numUsableCores, !isDriver)
// 设置端口
if (isDriver) {
conf.set(DRIVER_PORT, rpcEnv.address.port)
}
// 创建具有给定名称的类的实例,可能使用我们的conf初始化它
def instantiateClass[T](className: String): T = {
val cls = Utils.classForName(className)
// 寻找一个构造函数接受一个SparkConf和一个布尔值isDriver,
// 然后一个只接受SparkConf,然后一个不带参数
try {
cls.getConstructor(classOf[SparkConf], java.lang.Boolean.TYPE)
.newInstance(conf, java.lang.Boolean.valueOf(isDriver))
.asInstanceOf[T]
} catch {
case _: NoSuchMethodException =>
try {
cls.getConstructor(classOf[SparkConf]).newInstance(conf).asInstanceOf[T]
} catch {
case _: NoSuchMethodException =>
cls.getConstructor().newInstance().asInstanceOf[T]
}
}
}
// 如果未设置属性,则创建由给定SparkConf属性命名的类的实例,可能使用我们的conf初始化它
def instantiateClassFromConf[T](propertyName: ConfigEntry[String]): T = {
instantiateClass[T](conf.get(propertyName))
}
// 序列化器
val serializer = instantiateClassFromConf[Serializer](SERIALIZER)
logDebug(s"Using serializer: ${serializer.getClass}")
//序列化管理器
//为各种Spark组件配置序列化,压缩和加密的组件,包括自动选择用于shuffle的[[Serializer]]
val serializerManager = new SerializerManager(serializer, conf, ioEncryptionKey)
//关闭序列化器
//使用Java内置序列化的Spark序列化程序
val closureSerializer = new JavaSerializer(conf)
def registerOrLookupEndpoint(
name: String, endpointCreator: => RpcEndpoint):
RpcEndpointRef = {
if (isDriver) {
logInfo("Registering " + name)
//使用名称注册[[RpcEndpoint]]并返回其[[RpcEndpointRef]]
rpcEnv.setupEndpoint(name, endpointCreator)
} else {
//通过名称检索位于驱动程序中的`RpcEndpointRef`
RpcUtils.makeDriverRef(name, conf, rpcEnv)
}
}
//广播管理器
val broadcastManager = new BroadcastManager(isDriver, conf, securityManager)
//map输出跟踪器
//驱动程序端类,用于跟踪阶段的map输出的位置
val mapOutputTracker = if (isDriver) {
new MapOutputTrackerMaster(conf, broadcastManager, isLocal)
} else {
new MapOutputTrackerWorker(conf)
}
//由于MapOutputTrackerEndpoint需要MapOutputTracker本身
//,因此必须在初始化后分配trackerEndpoint
mapOutputTracker.trackerEndpoint=registerOrLookupEndpoint
(MapOutputTracker.ENDPOINT_NAME,
new MapOutputTrackerMasterEndpoint(rpcEnv,
mapOutputTracker.asInstanceOf[MapOutputTrackerMaster], conf))
// 让用户为Shuffle Manager指定短名称
val shortShuffleMgrNames = Map(
"sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName,
"tungsten-sort" -> classOf[org.apache.spark.shuffle.sort.SortShuffleManager].getName)
val shuffleMgrName = conf.get(config.SHUFFLE_MANAGER)
val shuffleMgrClass=shortShuffleMgrNames.getOrElse(
shuffleMgrName.toLowerCase(Locale.ROOT),shuffleMgrName)
//拖拽管理器
//驱动程序使用它注册shuffle,执行程序(或驱动程序中本地运行的任务)可以请求读取和写入数据。
val shuffleManager = instantiateClass[ShuffleManager](shuffleMgrClass)
//内存管理器
val memoryManager: MemoryManager = UnifiedMemoryManager(conf, numUsableCores)
//块管理端口
val blockManagerPort = if (isDriver) {
conf.get(DRIVER_BLOCK_MANAGER_PORT)
} else {
conf.get(BLOCK_MANAGER_PORT)
}
//外部拖拽客户端
val externalShuffleClient = if (conf.get(config.SHUFFLE_SERVICE_ENABLED)) {
val transConf = SparkTransportConf.fromSparkConf(conf, "shuffle", numUsableCores)
Some(new ExternalShuffleClient(transConf,securityManager,
securityManager.isAuthenticationEnabled(),
conf.get(config.SHUFFLE_REGISTRATION_TIMEOUT)))
} else {
None
}
//块管理器的主人
val blockManagerMaster = new BlockManagerMaster(registerOrLookupEndpoint(
BlockManagerMaster.DRIVER_ENDPOINT_NAME,
new BlockManagerMasterEndpoint(
rpcEnv,
isLocal,
conf,
listenerBus,
if (conf.get(config.SHUFFLE_SERVICE_FETCH_RDD_ENABLED)) {
externalShuffleClient
} else {
None
})),
conf, isDriver)
//块传输服务
//一种块传输服务,它使用Netty来获取一组块
val blockTransferService =
new NettyBlockTransferService(conf, securityManager, bindAddress, advertiseAddress,
blockManagerPort, numUsableCores, blockManagerMaster.driverEndpoint)
//块管理器。管理器在每个节点(驱动程序和执行程序)上运行
//,它提供用于在本地和远程将块放置和检索到各种存储(内存,磁盘和堆外)的接口。
// 注意:在稍后调用initialize()之前,blockManager无效
val blockManager = new BlockManager(
executorId,
rpcEnv,
blockManagerMaster,
serializerManager,
conf,
memoryManager,
mapOutputTracker,
shuffleManager,
blockTransferService,
securityManager,
externalShuffleClient)
//测量系统
val metricsSystem = if (isDriver) {
//不要立即为Driver启动测量系统。
//我们需要等待任务计划程序为我们提供应用程序ID。 然后我们可以启动测量系统。
MetricsSystem.createMetricsSystem(MetricsSystemInstances.DRIVER,
conf, securityManager)
} else {
// 我们需要在创建MetricsSystem之前设置执行程序ID
//,因为度量配置文件中指定的源和接收器将希望将此执行程序的ID合并到它们报告的度量标准中。
conf.set(EXECUTOR_ID, executorId)
val ms = MetricsSystem.createMetricsSystem(MetricsSystemInstances.EXECUTOR,
conf,securityManager)
ms.start()
ms
}
//输出提交协调员
//决定任务是否可以将输出提交到HDFS的权限。 使用“第一个提交者胜利”政策。
val outputCommitCoordinator = mockOutputCommitCoordinator.getOrElse {
new OutputCommitCoordinator(conf, isDriver)
}
val outputCommitCoordinatorRef = registerOrLookupEndpoint("OutputCommitCoordinator",
//此端点仅用于RPC
new OutputCommitCoordinatorEndpoint(rpcEnv, outputCommitCoordinator))
//由SparkEnv初始化
outputCommitCoordinator.coordinatorRef = Some(outputCommitCoordinatorRef)
val envInstance = new SparkEnv(
executorId,
rpcEnv,
serializer,
closureSerializer,
serializerManager,
mapOutputTracker,
shuffleManager,
broadcastManager,
blockManager,
securityManager,
metricsSystem,
memoryManager,
outputCommitCoordinator,
conf)
//添加对驱动程序创建的tmp目录的引用,我们将在调用stop()时删除此tmp目录
//,我们只需要为驱动程序执行此操作。 因为驱动程序可以作为服务运行
//,并且如果我们在sc停止时不删除此tmp目录,那么将创建太多的tmp目录
if (isDriver) {
//createTempDir:在给定的父目录中创建一个临时目录。 当VM关闭时,将自动删除该目录
//getLocalDir:获取临时目录的路径
val sparkFilesDir = Utils.createTempDir(Utils.getLocalDir(conf), "userFiles").getAbsolutePath
envInstance.driverTmpDir = Some(sparkFilesDir)
}
envInstance
}