Spark容错机制剖析

在一个分布式系统中,非常重要的一点就是容错性,Spark也不例外,当它机器发生故障的时候,可以很轻松的应对。本篇容错机制的剖析主要针对Standalone模式进行分析。

阅读本篇文章之前,你可以查看之前的【Spark源码解读之Master剖析】以及【Spark源码解读之Worker剖析】的文章,该篇是基于之前文章的补充。

在一个Spark集群中,有各种角色,Executor、Worker、Master等。下面来分析它们发生故障的时候该如何解决。

Executor异常退出

当Executor因为故障退出,那么势必影响运行在其上的任务无法正常运行。在前面【Spark源码解读之Worker剖析】一文中,通过源码我们了解到,启动Worker节点它会启动CoarseGrainedExecutorBackend进程,一旦收到EXITED退出状态,那么它会向Worker节点发送ExecutorStateChange的消息,接着又向Master转发ExecutorStateChange消息,在收到消息之后,Master会做以下几件事情:

  1. 找到占有Executor的Application的ApplicationInfo,以及Executor对应的ExecutorInfo。
  2. 将ExecutorInfo的状态改为EXITED
  3. EXITED也属于Executor完成状态,所以会将ExecutorInfo从ApplicationInfo和WorkerInfo中删除。
  4. 由于Executor是非正常退出,那么Master会调用schedule方法重新进行资源的调度。

Worker异常退出

当Worker节点发生故障,异常退出的时候,它会启动一个shutdownHook线程,在这个线程内调用killProcess方法主动杀死Executor的后台进程CoarseGrainedExecutorBackend进程,然后收到进程返回的EXITED状态,Worker会向Master发送ExecutorStateChanged消息,由于Worker发生故障宕机了,不会发送心跳报告给Master,所以Master收到worker的心跳报告,那么它会该Worker节点的WorkerInfo信息,然后将该Worker中的所有Executor以LOST的状态同步更新到Driver Application,最后Master还会重新调度Driver,将任务分配到其他Worker节点中执行。

/**
    * 启动Executor进程
    */
  def start() {
    //创建JAVA线程
    workerThread = new Thread("ExecutorRunner for " + fullId) {
      override def run() { fetchAndRunExecutor() }
    }
    workerThread.start()
    // Shutdown hook that kills actors on shutdown.
    shutdownHook = new Thread() {
      override def run() {
        killProcess(Some("Worker shutting down"))
      }
    }
    Runtime.getRuntime.addShutdownHook(shutdownHook)
  }
/**
   * Kill executor process, wait for exit and notify worker to update resource status.
   *
   * @param message the exception message which caused the executor's death
   */
  private def killProcess(message: Option[String]) {
    var exitCode: Option[Int] = None
    if (process != null) {
      logInfo("Killing process!")
      if (stdoutAppender != null) {
        stdoutAppender.stop()
      }
      if (stderrAppender != null) {
        stderrAppender.stop()
      }
      process.destroy()
      exitCode = Some(process.waitFor())
    }
    worker ! ExecutorStateChanged(appId, execId, state, message, exitCode)
  }

Master异常退出

假设在Standalone集群中,我们只有一个master,那么当它发生故障的时候会发生什么事呢?

  1. 当Executor上任务的执行完毕,需要对资源进行回收时。在SparkContext中我们调用stop方法来停止任务,Driver会向给自己服务的Executor发送StopExecutor消息对资源进行回收,Master虽然跑路了,但是Driver依然持有这些Executor,只是Master收不到DisassociatedEvent消息,但是CoarseGrainedExecutorBackend任然可以收到该消息,退出进程,所以说Master挂掉,对于如果Worker,Executor正常运行,对于资源的回收没有任何问题。
  2. 如果此时Executor再发生异常,Worker节点无法告知Master节点,也不能通过Driver重新调度,所以此时Executor上的任务无法执行,资源也无法回收。
  3. 如果此时Worker节点再发生异常,那么Worker和Executor都将停止服务,由于Master无法收到消息,该节点上的任务也执行失败,Driver提交的任务也无法执行,Worker节点资源无法被利用。
  4. 如果有新的Driver提交任务也无法成功。

可见,对于一个集群,只有一个Master是不可行的。因此我们需要HA方式来解决单点故障。这里涉及到两种机制。

持久化引擎:

  • ZookeeperPersistenceEngine:基于Zookeeper实现的持久化引擎。
  • FileSystemPersistenceEngine:基于文件系统的持久化引擎。

领导选举机制:

  • ZookeeperLeaderElectionAgent:对Zookeeper提供的选举机制的代理。
  • MoarchyLeaderAgent:默认的选举机制。

默认的情况下,Spark不提供故障恢复的能力。

val RECOVERY_MODE = conf.get("spark.deploy.recoveryMode", "NONE")
val RECOVERY_DIR = conf.get("spark.deploy.recoveryDirectory", "")

所以当我们没有设置这两个参数的时候,RECOVERY_MODENONE

如果使用FileSystemPersistenceEngine时,对应的领导选举机制是MoarchyLeaderAgent选举机制,我们可以将参数spark.deploy.recoveryMode设置为FILESYSTEM,然后可以通过给FileSystemPersistenceEngine设置构造参数来设置RECOVERY_DIR的值。

如果使用ZookeeperPersistenceEngine时,对应的领导选举机制为ZookeeperLeaderElectionAgent,可以通过设置参数spark.deploy.recoveryModeZOOKEEPER。这时集群会通过Zookeeper来实现自动故障转移。

在后续的文章中,会接着探讨Spark的选举机制以及基于Yarn和Mesos的集群部署模式,欢迎持续关注。

欢迎加入大数据学习交流群:731423890

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值