Spark技术内幕:Master的故障恢复
Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源码实现 详细阐述了使用ZK实现的Master的HA,那么Master是如何快速故障恢复的呢?
处于Standby状态的Master在接收到org.apache.spark.deploy.master.ZooKeeperLeaderElectionAgent发送的ElectedLeader消息后,就开始通过ZK中保存的Application,Driver和Worker的元数据信息进行故障恢复了,它的状态也从RecoveryState.STANDBY变为RecoveryState.RECOVERING了。当然了,如果没有任何需要恢复的数据,Master的状态就直接变为RecoveryState.ALIVE,开始对外服务了。
一方面Master通过
beginRecovery(storedApps, storedDrivers, storedWorkers)
恢复Application,Driver和Worker的状态,一方面通过
recoveryCompletionTask = context.system.scheduler.scheduleOnce(WORKER_TIMEOUT millis, self,
CompleteRecovery)
在60s后主动向自己发送CompleteRecovery的消息,开始恢复数据完成后的操作。
首先看一下如何通过ZooKeeperLeaderElectionAgent提供的接口恢复数据。
override def readPersistedData(): (Seq[ApplicationInfo], Seq[DriverInfo], Seq[WorkerInfo]) = {
val sortedFiles = zk.getChildren().forPath(WORKING_DIR).toList.sorted // 获取所有的文件
val appFiles = sortedFiles.filter(_.startsWith("app_")) //获取Application的序列化文件
val apps = appFiles.map(deserializeFromFile[ApplicationInfo]).flatten //将Application的元数据反序列化
val driverFiles = sortedFiles.filter(_.startsWith("driver_")) //获取Driver的序列化文件
val drivers = driverFiles.map(deserializeFromFile[DriverInfo]).flatten //将Driver的元数据反序列化
val workerFiles = sortedFiles.filter(_.startsWith("worker_")) // 获取Worker的序列化文件
val workers = workerFiles.map(deserializeFromFile[WorkerInfo]).flatten // 将Worker的元数据反序列化
(apps, drivers, workers)
}
获取了原来的Master维护的Application,Driver和Worker的列表后,当前的Master通过beginRecovery来恢复它们的状态。
恢复Application的步骤:
- 置待恢复的Application的状态为UNKNOWN,向AppClient发送MasterChanged的消息
- AppClient收到后改变其保存的Master的信息,包括URL和Master actor的信息,回复MasterChangeAcknowledged(appId)
- Master收到后通过appId后将Application的状态置为WAITING
- 检查如果所有的worker和Application的状态都不是UNKNOWN,那么恢复结束,调用completeRecovery()
恢复Worker的步骤:
- 重新注册Worker(实际上是更新Master本地维护的数据结构),置状态为UNKNOWN
- 向Worker发送MasterChanged的消息
- Worker收到消息后,向Master回复 消息WorkerSchedulerStateResponse,并通过该消息上报executor和driver的信息。
- Master收到消息后,会置该Worker的状态为ALIVE,并且会检查该Worker上报的信息是否与自己从ZK中获取的数据一致,包括executor和driver。一致的executor和driver将被恢复。对于Driver,其状态被置为RUNNING。
- 检查如果所有的worker和Application的状态都不是UNKNOWN,那么恢复结束,调用completeRecovery()
def beginRecovery(storedApps: Seq[ApplicationInfo], storedDrivers: Seq[DriverInfo],
storedWorkers: Seq[WorkerInfo]) {
for (app <- storedApps) { // 逐个恢复Application
logInfo("Trying to recover app: " + app.id)
try {
registerApplication(app)
app.state = ApplicationState.UNKNOWN
app.driver ! MasterChanged(masterUrl, masterWebUiUrl) //向AppClient发送Master变化的消息,AppClient会回复MasterChangeAcknowledged
} catch {
case e: Exception => logInfo("App " + app.id + " had exception on reconnect")
}
} for (driver <- storedDrivers) {
// Here we just read in the list of drivers. Any drivers associated with now-lost workers
// will be re-launched when we detect that the worker is missing.
drivers += driver // 在Worker恢复后,Worker会主动上报运行其上的executors和drivers从而使得Master恢复executor和driver的信息。
} for (worker <- storedWorkers) { //逐个恢复Worker
logInfo("Trying to recover worker: " + worker.id)
try {
registerWorker(worker) //重新注册Worker
worker.state = WorkerState.UNKNOWN
worker.actor ! MasterChanged(masterUrl, masterWebUiUrl) //向Worker发送Master变化的消息,Worker会回复WorkerSchedulerStateResponse
} catch {
case e: Exception => logInfo("Worker " + worker.id + " had exception on reconnect")
}
}
}
通过下面的流程图可以更加清晰的理解这个过程:
//调用时机
// 1. 在恢复开始后的60s会被强制调用
// 2. 在每次收到AppClient和Worker的消息回复后会检查如果Application和worker的状态都不为UNKNOWN,则调用
def completeRecovery() {
// Ensure "only-once" recovery semantics using a short synchronization period.
synchronized {
if (state != RecoveryState.RECOVERING) { return }
state = RecoveryState.COMPLETING_RECOVERY
} // Kill off any workers and apps that didn't respond to us. 删除在60s内没有回应的app和worker
workers.filter(_.state == WorkerState.UNKNOWN).foreach(removeWorker)
apps.filter(_.state == ApplicationState.UNKNOWN).foreach(finishApplication) // Reschedule drivers which were not claimed by any workers
drivers.filter(_.worker.isEmpty).foreach { d => // 如果driver的worker为空,则relaunch。
logWarning(s"Driver ${d.id} was not found after master recovery")
if (d.desc.supervise) {
logWarning(s"Re-launching ${d.id}")
relaunchDriver(d)
} else {
removeDriver(d.id, DriverState.ERROR, None)
logWarning(s"Did not re-launch ${d.id} because it was not supervised")
}
} state = RecoveryState.ALIVE
schedule()
logInfo("Recovery complete - resuming operations!")
}
但是对于一个拥有几千个节点的集群来说,60s设置的是否合理?毕竟现在没有使用Standalone模式部署几千个节点的吧?因此硬编码60s看上去也十分合理,毕竟都是逻辑很简单的调用,如果一些节点60S没有返回,那么下线这部分机器也是合理的。
通过设置spark.worker.timeout,可以自定义超时时间。
Spark技术内幕:Master的故障恢复的更多相关文章
- Spark技术内幕:Stage划分及提交源码分析
http://blog.csdn.net/anzhsoft/article/details/39859463 当触发一个RDD的action后,以count为例,调用关系如下: org.apache. ...
- Spark技术内幕: Task向Executor提交的源码解析
在上文<Spark技术内幕:Stage划分及提交源码分析>中,我们分析了Stage的生成和提交.但是Stage的提交,只是DAGScheduler完成了对DAG的划分,生成了一个计算拓扑, ...
- Spark技术内幕: Task向Executor提交的源代码解析
在上文<Spark技术内幕:Stage划分及提交源代码分析>中,我们分析了Stage的生成和提交.可是Stage的提交,仅仅是DAGScheduler完毕了对DAG的划分,生成了一个计算拓 ...
- Spark技术内幕:Client,Master和Worker 通信源码解析
http://blog.csdn.net/anzhsoft/article/details/30802603 Spark的Cluster Manager可以有几种部署模式: Standlone Mes ...
- Spark技术内幕:Client,Master和Worker 通信源代码解析
Spark的Cluster Manager能够有几种部署模式: Standlone Mesos YARN EC2 Local 在向集群提交计算任务后,系统的运算模型就是Driver Program定义 ...
- Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源码实现
如果Spark的部署方式选择Standalone,一个采用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark可以 ...
- Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源代码实现
假设Spark的部署方式选择Standalone,一个採用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark能够 ...
- 我的第一本著作:Spark技术内幕上市!
现在各大网站销售中! 京东:http://item.jd.com/11770787.html 当当:http://product.dangdang.com/23776595.html 亚马逊:http ...
- Spark技术内幕: Shuffle详解(一)
通过上面一系列文章,我们知道在集群启动时,在Standalone模式下,Worker会向Master注册,使得Master可以感知进而管理整个集群:Master通过借助ZK,可以简单的实现HA:而应用 ...
随机推荐
- 【 lca倍增模板】
题目描述 对于 n(<100000)个点 n-1 条掉权值的边,有 m 个询问,每条询问求两个结点之间的路径上边权的最小值 输入 第一行 n,表示结点个数,接下来 n-1 行,每行 a b w ...
- [Codeforces]871D Paths
失踪OJ回归. 毕竟这样的数论没做过几道,碰上一些具体的应用还是无所适从啊.小C还是借助这题大致摸索一下莫比乌斯函数吧. Description 有n个点,标号为1~n,为这n个点建一张无向图.两个点 ...
- UVA 3713 Astronauts
The Bandulu Space Agency (BSA) has plans for the following three space missions: • Mission A: Landin ...
- Codeforces Round#403 (Div. 1)
唉,昨天晚上迷迷糊糊地去打cf,结果fst两题,掉回蓝了... A.Andryusha and Colored Balloons 题意:给定一棵树,任意两个距离小等于二的点不能染相同的颜色,求最小颜色 ...
- java版的类似飞秋的局域网在线聊天项目
原文链接:http://www.cnblogs.com/wangleiblog/articles/5323305.html 转载请注明 最近在弄一个java版的局域网在线聊天项目,功能跟飞秋差不多.p ...
- VC++ 6.0中添加库文件和头文件
附加头文件包含 VC6.0中: VC6.0默认include包含路径:Tools>Options>Directories>Include files. 对于特定项目的头文件包含,在& ...
- new File()
首先 File 类是对文件系统的映射 并不是硬盘上真实的文件所以 new File("xxx.xxx") 只是在内存中创建File文件映射对象,而并不会在硬盘中创建文件 如果需要创 ...
- linux修改root账户的用户名所得的教训
之前linux服务器的密码被别人改过, 然后叫服务器相关的负责人重置了root账户(服务器负责人在客户所在公司), 重置好之后, 领导叫更改下root 用户名和密码, 于是我二话不说就开始找方法, 找 ...
- QRCode.js:使用 JavaScript 生成二维码
什么是 QRCode.js? QRCode.js 是一个用于生成二维码的 JavaScript 库.主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库. 基本用法 ...
- 详解Tomcat配置JVM参数步骤
这里向大家描述一下如何使用Tomcat配置JVM参数,Tomcat本身不能直接在计算机上运行,需要依赖于硬件基础之上的操作系统和一个Java虚拟机.您可以选择自己的需要选择不同的操作系统和对应的JDK ...