Spark ZooKeeper数据恢复

 

Spark使用ZooKeeper进行数据恢复的逻辑过程如下:

1.初始化:创建<CuratorFramwork,LeaderLatch,LeaderLatchListener>用于选举

            创建CuratorFramework用于数据恢复。

 

2.选举:启动LeaderLatch,Curator开始接管选举工作了。

3.恢复:当某个Master被选举为Leader后,就会调用LeaderLatchListener的isLeader()方法,这个方法内部开始进行逻辑上的数据恢复工作,具体细节是这样的,向Master发送ElectedLeader消息,Master从ZooKeeperPersistenceEngine中读取数据到内存缓存中,ZooKeeperPersistenceEngine从ZooKeeper的/spark/master_status/目录下读取storedApps,storedDrivers,storedWorkers。

 

下面来进行一下源码的走读,方便日后回忆。

1.初始化:Master启动时创建ZooKeeperLeaderElectionAgent和 ZooKeeperPersistenceEngine,前者用于选举,后者用于数据恢复。

Master初始化源码如下:

   

 case "ZOOKEEPER" =>
        logInfo("Persisting recovery state to ZooKeeper")
        val zkFactory =
          new ZooKeeperRecoveryModeFactory(conf, SerializationExtension(context.system))
        (zkFactory.createPersistenceEngine(), zkFactory.createLeaderElectionAgent(this))
复制代码
private[master] class ZooKeeperRecoveryModeFactory(conf: SparkConf, serializer: Serialization)
  extends StandaloneRecoveryModeFactory(conf, serializer) {

  def createPersistenceEngine(): PersistenceEngine = {
    new ZooKeeperPersistenceEngine(conf, serializer)
  }

  def createLeaderElectionAgent(master: LeaderElectable): LeaderElectionAgent = {
    new ZooKeeperLeaderElectionAgent(master, conf)
  }
}
复制代码

 

 

复制代码
private[master] class ZooKeeperPersistenceEngine(conf: SparkConf, val serialization: Serialization)
  extends PersistenceEngine
  with Logging {

  private val WORKING_DIR = conf.get("spark.deploy.zookeeper.dir", "/spark") + "/master_status"
  //创建zookeeper客户端
  private val zk: CuratorFramework = SparkCuratorUtil.newClient(conf)

  //创建WORKING_DIR目录
  SparkCuratorUtil.mkdir(zk, WORKING_DIR)
}
复制代码

 

 

 

创建ZooKeeperLeaderElectionAgent时会创建用于选举的CuratorFramwork,LeaderLatch,LeaderLatchListener。其中的LeaderLatch用于选举Leader,当某个LeaderLatch被选举为Leader之后,就会调用对应的LeaderLatchListener的isLeader(),如下:

复制代码
private[master] class ZooKeeperLeaderElectionAgent(val masterActor: LeaderElectable,
    conf: SparkConf) extends LeaderLatchListener with LeaderElectionAgent with Logging  {

  val WORKING_DIR = conf.get("spark.deploy.zookeeper.dir", "/spark") + "/leader_election"

  private var zk: CuratorFramework = _
  private var leaderLatch: LeaderLatch = _
  private var status = LeadershipStatus.NOT_LEADER

  start()

  private def start() {
    logInfo("Starting ZooKeeper LeaderElection agent")
    zk = SparkCuratorUtil.newClient(conf)
    leaderLatch = new LeaderLatch(zk, WORKING_DIR)
    leaderLatch.addListener(this)
    leaderLatch.start()
  }
复制代码

 

2.选举,调用LeaderLatch的start开始进行选举

 

3.数据恢复:如果某个master被成功选举为alive master,那么会调用isLeader()。这个方法内部会向Master发送ElectedLeader消息,然后Master会从ZookeeperPersistenceEngin中也就是ZooKeeper中读取storedApps,storedDrivers,storedWorkers并将他们恢复到内存缓存中去。

   

复制代码
  override def isLeader() {
    synchronized {
      // could have lost leadership by now.
      if (!leaderLatch.hasLeadership) {
        return
      }

      logInfo("We have gained leadership")
      updateLeadershipStatus(true)
    }
  }
复制代码
复制代码
  private def updateLeadershipStatus(isLeader: Boolean) {
    if (isLeader && status == LeadershipStatus.NOT_LEADER) {
      status = LeadershipStatus.LEADER
      masterActor.electedLeader()
    } else if (!isLeader && status == LeadershipStatus.LEADER) {
      status = LeadershipStatus.NOT_LEADER
      masterActor.revokedLeadership()
    }
  }
复制代码

 

 

开始真正的数据恢复工作:

复制代码
  case ElectedLeader => {
      val (storedApps, storedDrivers, storedWorkers) = persistenceEngine.readPersistedData()
      state = if (storedApps.isEmpty && storedDrivers.isEmpty && storedWorkers.isEmpty) {
        RecoveryState.ALIVE
      } else {
        RecoveryState.RECOVERING
      }
      logInfo("I have been elected leader! New state: " + state)
      if (state == RecoveryState.RECOVERING) {
        beginRecovery(storedApps, storedDrivers, storedWorkers)
        recoveryCompletionTask = context.system.scheduler.scheduleOnce(WORKER_TIMEOUT millis, self,
          CompleteRecovery)
      }
    }
复制代码

 

持久化数据存储在ZooKeeper中的/spark/master_status目录下。以app为例,当向ZooKeeperPersistenceEngine中写入app时,假设这个appId是1,那么就会创建一个/spark/master_status/app_1的持久化节点,节点数据内容就是序列化的app对象。

 

/spark/master_status

                               /app_appid

                              /worker_workerId

                             /driver_driverId

 

posted @   王宝生  阅读(1161)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示