Spark的AppStatusStore类简介及原理梳理

  本文还是按照提问式学习方式来一起学习AppStatusStore这个类

AppStatusStore的作用是什么?

  AppStatusStores是用来存储Application的状态数据,Spark Web UI及REST API需要的数据都取自它。之前在写度量系统时
 

AppStatusStore在什么时候初始化?如何被创建的?

  在SparkContext初始化的时候,有这样一句代码,这就是AppStatusStore的初始化代码
 1 _statusStore = AppStatusStore.createLiveStore(conf)  
  
  并且创建的代码是这样的
1 def createLiveStore(conf: SparkConf): AppStatusStore = {
2     val store = new ElementTrackingStore(new InMemoryStore(), conf)
3     val listener = new AppStatusListener(store, conf, true)
4     new AppStatusStore(store, listener = Some(listener))
5 }

  这时候看到store、listener肯定是一脸懵,没关系,后面我们会讲这两个的作用

 

AppStatusStore如何使用呢?

  其实很简单,通过它提供的几个方法,就能看出该如何使用它
1 def applicationInfo(): v1.ApplicationInfo //获取app的信息
2 def jobsList(statuses: JList[JobExecutionStatus]): Seq[v1.JobData] //获取job的集合
3 def job(jobId: Int): v1.JobData //获取job
4 def activeStages(): Seq[v1.StageData] //获取激活状态的stages
5 def taskCount(stageId: Int, stageAttemptId: Int): Long //获取task数量
6 .....

  通过上面的方法,可以看出 AppStatusStore 能获取到各种Job、app相关的信息,这些信息能提供给Spark UI进行展示

   看完 AppStatusStore 提供的这些方法后,这时候大家都会冒出好几个问题:
1 AppStatusStore 如何存储这些数据的?或者说这些数据存在哪里?
2 AppStatusStore 存储的数据结构是怎么样的?
3 AppStatusStore 什么时候存储这些数据的?

  现在我们一个个问题来解答

 AppStatusStore 如何存储这些数据的?或者说这些数据存在哪里?

  如何存储,就要从 AppStatusStore 的结构说起
  这里,我用简单的伪代码来解答这个问题
 1 private[spark] class AppStatusStore(val store: KVStore, val listener: Option[AppStatusListener] = None) {
 2     //获取环境信息
 3     def environmentInfo(): v1.ApplicationEnvironmentInfo = {
 4         val klass = classOf[ApplicationEnvironmentInfoWrapper]
 5         store.read(klass, klass.getName()).info
 6     }
 7 
 8     //获取job信息
 9     def job(jobId: Int): v1.JobData = {
10         store.read(classOf[JobDataWrapper], jobId).info
11     }
12     
13     def activeStages(): Seq[v1.StageData] = {
14         listener.map(_.activeStages()).getOrElse(Nil)
15     }
16 }

  这时候我们可以看到,AppStatusStore的environmentInfo()、job()、activeStages()方法展示的数据,都是来源于外部传入的 store、listener,这些都是在 AppStatusStore 被创建的时候传进来的,答案就在 上面的问题:AppStatusStore在什么时候初始化?如何被创建的? 这里 

1 def createLiveStore(conf: SparkConf): AppStatusStore = {
2     val store = new ElementTrackingStore(new InMemoryStore(), conf)
3     val listener = new AppStatusListener(store, conf, true)
4     new AppStatusStore(store, listener = Some(listener))
5 }

AppStatusStore 存储的数据结构是怎么样的?

  通过上面的伪代码,我们可以知道,AppStatusStore 的显示数据主要存储在 store: ElementTrackingStore 和 listener:AppStatusListener 两个元素中,现在就来分析一下
 
  ElementTrackingStore 伪代码如下
 1 private[spark] class ElementTrackingStore(store: KVStore, conf: SparkConf) extends KVStore {
 2     //写入数据
 3     override def write(value: Any): Unit = store.write(value)
 4 
 5     //删除store中的数据
 6     override def delete(klass: Class[_], naturalKey: Any): Unit = store.delete(klass, naturalKey)
 7     
 8     //获取store中的view
 9     override def view[T](klass: Class[T]): KVStoreView[T] = store.view(klass)
10     
11     //获取store的元素个数
12     override def count(klass: Class[_]): Long = store.count(klass)
13 }

  从这段代码可以看出,ElementTrackingStore 的写、读取、删除等操作,都是基于 store: KVStore 之上,这个store是什么呢?回顾上面的代码,store来源于 InMemoryStore,所以 ElementTrackingStore 就是对 InMemoryStore 进行了一次封装

  1 val store = new ElementTrackingStore(new InMemoryStore(), conf) 
  
  所以这样看来 ElementTrackingStore 也很简单,主要基于 InMemoryStore 的读写删操作(当然还包括定时清理数据的触发器,这个自己研究即可,放入进来讲容易打乱思路)
   
  那么大家是不是冒出一个问题:store 什么时候会被写入数据?
  其实这时候我们本应该讲 listener:AppStatusListener 的数据存储结构,但是在我看来,这两个问题都是对 listener:AppStatusListener 做好解释,因为 listener:AppStatusListener 的作用就是:
  1、当监听被触发的时候,将数据写入到 store
  2、listener:AppStatusListener 自身内部也保存了一点状态数据,并提供给 AppStatusStore 用于展示
 
  我们来看 listener:AppStatusListener 是如何被创建的,在问题:AppStatusStore在什么时候初始化?如何被创建的?中就已经描述了
 1 val listener = new AppStatusListener(store, conf, true)  
 
  将store传入,待会Listener被触发,就会把相应数据存入到store中,可以看下面 AppStatusListener 的伪代码
 1 private[spark] class AppStatusListener(
 2     kvstore: ElementTrackingStore,
 3     conf: SparkConf,
 4     live: Boolean,
 5     lastUpdateTime: Option[Long] = None) extends SparkListener with Logging {
 6   
 7   //application结束时触发
 8   override def onApplicationEnd(event: SparkListenerApplicationEnd): Unit = {
 9     ...
10     kvstore.write(new ApplicationInfoWrapper(appInfo))
11   }
12 
13   //Job启动时触发
14   override def onJobStart(event: SparkListenerJobStart): Unit = {
15     ...
16       kvstore.write(uigraph)
17     }
18   }
19   
20   private val liveStages = new ConcurrentHashMap[(Int, Int), LiveStage]()
21   private def getOrCreateStage(info: StageInfo): LiveStage = {
22     val stage = liveStages.computeIfAbsent((info.stageId, info.attemptNumber),
23       new Function[(Int, Int), LiveStage]() {
24         override def apply(key: (Int, Int)): LiveStage = new LiveStage()
25       })
26     stage.info = info
27     stage
28   }
29   
30   def activeStages(): Seq[v1.StageData] = {
31     liveStages.values.asScala
32       .filter(_.info.submissionTime.isDefined)
33       .map(_.toApi())
34       .toList
35       .sortBy(_.stageId)
36   }
37 }

  通过 onApplicationEnd() 、onJobStart() 方法可以看出,一旦Lisntener被触发,就会将信息写入到store中

  而通过 getOrCreateStage() 、activeStages() 方法可以看出,Listener内部也会保存一些成员变量 来 记录一些 状态信息,并通过 activeStages() 方法提供给 AppStatusStore 对外展示
   所以在这里就解答了:AppStatusStore在什么时候初始化?如何被创建的?问下中,大家对 store、listener作用和两者之间的关系弄明白了
 
  看到这里,有人应该会冒出这样的问题:什么时候会调用到Listenr的这些方法?或者说,什么时候Listener注册到Spark系统中呢?接下来来解答这个问题
 

什么时候会调用到Listenr的这些方法?或者说,什么时候Listener注册到Spark系统中呢?

  我们知道在SparkContext中,初始化了 AppStatusStore
 1 _statusStore = AppStatusStore.createLiveStore(conf)  
  
  紧接着,就在下一句,将Listener注册给Spark的listenerBus, listenerBus是负责管理Spark的监听器的组件
 1 listenerBus.addToStatusQueue(_statusStore.listener.get)  
 
  对 listenerBus 有兴趣的同学,可以参考我的listenerBus文章:

posted @ 2022-01-09 14:31  白羊座怪蜀黍  阅读(323)  评论(0编辑  收藏  举报