Spark 2.3 源码分析之事件总线 ListenerBus

一、事件总线介绍

Spark 定义了一个特质 ListenerBus,可以接受事件并且将事件提交到对应事件的监听器。

该特征主要有一个 listenersPlusTimers成员,用于维护所有注册的监听器,其数据结构是一个线程安全的CopyOnWriteArrayList[(L, Option[Timer])]。

该特征还有几个主要的函数:

  • listener:返回listenersPlusTimers中所有的监听器
  • getTimer:返回一个Timer用于统计事件处理时间
  • addListener::添加 listener
  • removeListener:删除 listener
  • removeListenerOnError:内部调用 removeListener,可由子类覆盖
  • postToAll: 把事件发送给所有的 listener,虽然CopyOnWriteArrayList 是线程安全的,但 postAll 引入了“先检查后运行”的逻辑,因此该方法不是线程安全的。
  • doPostEvent:给特定 listener 发送事件,该方法具体需要子类实
  • findListenersByClass:根据类型查找 listener 列表

二、ListenerBus 继承体系

Spark 2.3 源码分析之事件总线 ListenerBus_第1张图片

上图是 spark 2.3.0 版本事件总线的继承关系,版本不同,会略有不同。

每个 ListenerBus 用于将不同的 Event 投递到不同的 Listener 中,下面以主要分析下 LiveListenerBus。

三、LiveListenerBus 详解

LiveListenerBus 不再继承 SparkListenerBus,和其他 ListenerBus 不同的是, LiveListenerBus 是将事件广播给事件队列集合中的AsyncEventQueue,然后每个AsyncEventQueue中都有一个线程不断从自身成员变量eventQueue中获取事件,将事件异步投递给监听器,达到实时刷新UI界面数据的效果。

3.1、LiveListenerBus 中的属性:

  • sparkContext:spark上下文,维护者好多组件
  • metrics:度量系统的数据源
  • started:标记 LiveListenerBus 的启动状态的 AtomicBoolean 类型的变量
  • stopped:标记LiveListenerBus的停止状态的 AtomicBoolean 类型的变量
  • droppedEventsCounter:使用 AtomicLong 类型对删除的事件进行计数,每当日志打印了 droppedEventsCounter 后,会将droppedEventsCounter 重置为0
  • lastReportTimestamp:记录最后一次日志打印 droppedEventsCounter 的时间戳
  • queues:事件队列集合包括shared、sppStatus、eventLog和executorManagement
  • queuedEvents:sparkListenerEvent事件集合

3.2、启动LiveListenerBus(start)

  开始向附加的监听器发送事件。 在事件总线启动之前发送所有缓冲的事件,然后在事件总线运行时异步监听任何其他事件。 此方法只调用一次。

代码清单3-1Spark 2.3 源码分析之事件总线 ListenerBus_第2张图片

    1. 查看是否已经启动,若已启动则抛出异常。
    2. 遍历事件队列集合。
      • 启动事件队列,调用了AsyncEventQueue的start(代码清单4-1)方法,主要是启动一个异步处理事件的线程。
      • 遍历事件集合。
        • 将事件发送给事件队列下注册的所有监听器,调用了AsyncEventQueue的post(代码清单4-2)方法。
    3. 将LiveListenerBusMetrics注册到度量系统。

 

3.3、事件发送(post,postToAll)

    所有维护着LivelistenerBus的组件,通过post方法向事件队列发送事件。

代码清单3-2

Spark 2.3 源码分析之事件总线 ListenerBus_第3张图片

    1. 度量系统记录事件数+1
    2. 如果事件缓存为null,则表示事件总线已经启动(因为在启动时会先将缓存中的事件发送给事件队列处理),所以不需要同步,可以直接将事件发送给事件队列(调用postToQueues方法,代码清单3-3),结束后直接返回。
    3. 如果事件总线未启动,则需要同步向时间缓存quevedEvents中放入事件,结束后直接返回。
    4. 如果不符合2个3中的情况,则直接将事件发送给事件队列。

代码清单3-3

Spark 2.3 源码分析之事件总线 ListenerBus_第4张图片

四、AsyncEventQueue详解

  AsyncEventQueue继承了SparkListenerBus,实现了将事件异步投递给监听器,达到实时刷新UI界面的效果。

4.1、AsyncEventQueue的属性:

  • eventQueue:事件缓存,liveListenerBus post的事件,会放到这个缓存中。
  • eventCount: 事件计数器,waitUntilEmpty()中用到,使得该方法仅在队列中的事件被完全处理完时返回。
  • droppedEventsCounter:使用 AtomicLong 类型对删除的事件进行计数,每当日志打印了 droppedEventsCounter 后,会将droppedEventsCounter 重置为0
  • lastReportTimestamp:记录最后一次带引droppedEventsCounter的时间戳
  • logDroppedEvent:使用AtomicBollean标识是否记录删除事件
  • sc:sparkContext上下文
  • started:标记 LiveListenerBus 的启动状态的 AtomicBoolean 类型的变量
  • stopped:标记LiveListenerBus的停止状态的 AtomicBoolean 类型的变量
  • droppedEvents:度量系统中的时间删除计数器(counter)
  • processingTime:度量系统中的时间处理计时器(timer)
  • dispatchThread:异步事件处理线程

4.2、AsyncEventQueue启动(start)

启动异步线程以将事件分派给监听器

代码清单4-1

Spark 2.3 源码分析之事件总线 ListenerBus_第5张图片

Spark 2.3 源码分析之事件总线 ListenerBus_第6张图片

Spark 2.3 源码分析之事件总线 ListenerBus_第7张图片

此处只分析异步线程的工作流程dispatch

    1. 从eventQueue中获取事件
    2. 调用超类ListenerBus的postToAll(对监听器进行遍历,并调用SparkListenerBus的doPostEvent方法对事件进行匹配后执行监听器的对应方法)方法。

代码清单4-2

Spark 2.3 源码分析之事件总线 ListenerBus_第8张图片

负责将事件放到事件缓冲队列中

五、流程总结

Spark 的事件总线大致的流程:

Spark 2.3 源码分析之事件总线 ListenerBus_第9张图片Spark 2.3 源码分析之事件总线 ListenerBus_第10张图片

你可能感兴趣的:(spark)