要介绍LauncherBackend,首先介绍下LaucherServer。当Spark应用程序没有在用户应用程序中运行,而是运行在单独的进程中时,用户可以在用户应用程序中使用LauncherServer与Spark应用程序通信。LauncherServer将提供Socket连接的服务端,与Spark应用程序中的Socket连接的客户端通信。LaucherServer的工作原理如下图:
TaskSchedulerImpl的底层依赖于LauncherBackend,而LaucherBackend依赖于BackendConnection跟LaucherServer进行通信
- 1)调用LauncherBackend的connect方法创建BackendConnection,并且创建线程执行BackendConnection。构造BackendConnection的过程中,BackendConnection会和LaucherServer之间建立起Socket连接。BackendConnection(实现了java.lang.Runnable接口)将不断从Socket连接中读取LauncherServer发送的数据
- 2)调用LauncherBackend的setAppId方法或SetState方法,通过向Socket连接向LancherServer发送SetAppId消息或SetState消息
- 3)BackendConnection从Socket连接中读取到LauncherServer发送的Stop消息,然后调用LauncherBackend的fire
1 BackendConnection的实现
BackendConnection是LauncherBackend的内部组件,用于保持与LauncherServer的Socket连接,并通过此Socket连接收发消息。LauncherConnection提供了维护连接和收发消息的基本实现。
1.1 handle
handle是LauncherConnection提供的用于处理LauncherServer发送的消息的抽象方法
//org.apache.spark.launcher.LauncherConnection
protected abstract void handle(Message msg) throws IOException;
BackendConnection实现了LauncherConnection的handle方法,如下:
//org.apache.spark.launcher.LauncherBackend
override protected def handle(m: Message): Unit = m match {
case _: Stop =>
fireStopRequest()
case _ =>
throw new IllegalArgumentException(s"Unexpected message type: ${m.getClass().getName()}")
}
BackendConnection实现的handle方法只处理Stop这一咱消息。对于Stop消息,BackendConnection将调用外部类LauncherBackend的fireStopRequest方法停止Executor。
1.2 run
由于LauncherConnection实现了java.lang.Runnable接口,因此需要实现run方法。LauncherConnection的run方法用于从Socket客户端的输入流中读取LauncherServer发送的消息,并调用handle方法对消息进行处理。LauncerConnection的run方法同时也是一个模板方法。
//org.apache.spark.launcher.LauncherConnection
@Override
public void run() {
try {
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
while (!closed) {
Message msg = (Message) in.readObject();
handle(msg);
}
} catch (EOFException eof) {
// Remote side has closed the connection, just cleanup.
try {
close();
} catch (Exception unused) {
// no-op.
}
} catch (Exception e) {
if (!closed) {
LOG.log(Level.WARNING, "Error in inbound message handling.", e);
try {
close();
} catch (Exception unused) {
// no-op.
}
}
}
}
1.3 close
此方法用于关闭Socket客户端与LauncherServer的Socket服务端建立的连接,其实现代码清单如下:
//org.apache.spark.launcher.LauncherConnection
@Override
public void close() throws IOException {
if (!closed) {
synchronized (this) {
if (!closed) {
closed = true;
socket.close();
}
}
}
}
BackendConnection重写了LauncherConnection的close方法,其实现如下:
//org.apache.spark.launcher.LauncherBackend
override def close(): Unit = {
try {
super.close()
} finally {
onDisconnected()
_isConnected = false
}
}
BackendConnection重写的close方法首先调用了父类LauncherConnection的close方法关闭Socket连接,然后调用外部类LauncherBackend的onDisconnected方法。由于LauncherBackend的onDisconnected是个空方法,因此onDisconnected并不会有额外的效果。
2 LauncherBackend的实现
LauncherBackend是SchedulerBackend与LaucherServer通信的组件。其包含的属性有:
- clientThread:读取与LaucherServer建立的Socket连接上的消息的线程
- connection:即BackendConnection实例
- lastState:LauncherBackend的最后一次状态。
- _isConnected:clientThread是否与LauncherServer已经建立了Socket连接的状态
2.1 connect
用于和LauncherServer建立连接
//org.apache.spark.launcher.LauncherBackend
def connect(): Unit = {
val port = sys.env.get(LauncherProtocol.ENV_LAUNCHER_PORT).map(_.toInt)
val secret = sys.env.get(LauncherProtocol.ENV_LAUNCHER_SECRET)
if (port != None && secret != None) {
val s = new Socket(InetAddress.getLoopbackAddress(), port.get)
connection = new BackendConnection(s)
connection.send(new Hello(secret.get, SPARK_VERSION))
clientThread = LauncherBackend.threadFactory.newThread(connection)
clientThread.start()
_isConnected = true
}
}
- 1)创建与LauncherServer的Socket服务端建立连接的Socket。
- 2)通过此连接向LauncherServer发送Hello消息
- 3)创建并启动一个执行BackendConnection的run方法的线程
- 4)将_isConnected设置为true
2.2 setAppId
用于向LauncherServer发送SetAppId消息。SetAppId消息携带着应用程序的身份标识。
def setAppId(appId: String): Unit = {
if (connection != null) {
connection.send(new SetAppId(appId))
}
}
2.3 setState
用于向LaucherServer发送SetState消息。SetState消息携带着LauncherBackend的最后一次状态。
def setState(state: SparkAppHandle.State): Unit = {
if (connection != null && lastState != state) {
connection.send(new SetState(state))
lastState = state
}
}
2.4 fireStopRequest
用于启动一个调用onStopRequest方法的线程
private def fireStopRequest(): Unit = {
val thread = LauncherBackend.threadFactory.newThread(new Runnable() {
override def run(): Unit = Utils.tryLogNonFatalError {
onStopRequest()
}
})
thread.start()
}