Spark UI实现原理与事件监听机制
一、引言
Spark UI是了解spark任务运行情况的入口,也是进行spark任务性能优化与调试必不可少的工具。在Spark UI中可以查看job、stage、storage、environment、excutors和spark sql等信息,那么这都是怎么实现的,这些信息都是怎么获取到的呢?本文从源码的角度对Spark UI的信息获取方式与Spark的事件监听机制进行解析。
二、Spark UI实现原理与事件监听机制
Spark UI是driver中提供的一个web服务,其中展现了整个应用的运行信息,由此肯定各executors在运行过程中不断上报其运行信息与资源情况。SparkUI架构图如下,Spark采用事件监听、异步更新的方式来实现任务监控。为什么要使用事件监听机制?
- 假如采用函数调用、同步更新的方式,那么随着任务数和监控指标的增加,可能会因为Driver所在JVM的线程数有限而导致更新无法及时执行从而影响监控数据的更新。
- 分布式环境下可能因为网络问题等原因,导致同步调用线程被阻塞,线程被长时间占用。
- 将同步调用更换为异步事件,当前线程可以继续执行后续逻辑,这样整个系统的并发度会大大增加。
- 发送的事件会存入缓存,由定时调度器取出后,分配给监听此事件的监听器对监控数据进行更新。
如图所示:DAGScheduler是主要的产生各类SparkListenerEvent的源头,它将各种SparkListenerEvent发送到listenerBus的事件队列中,listenerBus通过定时器将SparkListenerEvent事件匹配到具体的SparkListener,改变SparkListener中的统计监控数据,最终由SparkUI的界面展示。Spark里定义了很多监听器SparkListener的实现,包括JobProgressListener、EnvironmentListener、StorageStatusListener、ExecutorsListener和RDDOperationGraphListener。
下面结合源码介绍下SparkUI的实现原理:
-
Spark UI是在
SparkContext.scala
中进行创建初始化的,每个spark应用有且仅有一个活跃的SparkContext。在一个Spark应用中,首先必需新建一个SparkContext,也就同时新建了Spark UI对象,可以通过spark.ui.enabled
关闭此功能。_ui = if (conf.getBoolean("spark.ui.enabled", true)) { Some(SparkUI.createLiveUI(this, _conf, listenerBus, _jobProgressListener, _env.securityManager, appName, startTime = startTime)) } else { // For tests, do not enable the UI None } // Bind the UI before starting the task scheduler to communicate // the bound port to the cluster manager properly _ui.foreach(_.bind())
-
SparkUI.createLiveUI创建SparkUI对象实际是调用下面的create方法,其主要工作是初始化几个事件监听者,并将其注册到事件总线上去。这是设计模式中典型的观察者模式,其中的关键则是SparkListenerBus的实现,即spark的事件监听机制的实现原理。
/** * Create a new Spark UI. * * @param sc optional SparkContext; this can be None when reconstituting a UI from event logs. * 参数sc,可选的SparkContext对象,当从事件日志中重建一个UI对象时它可以为None。 * @param jobProgressListener if supplied, this JobProgressListener will be used; otherwise, the * web UI will create and register its own JobProgressListener. * 参数 jobProgressListener:如果提供了就使用这个JobProgressListener, * 否则UI对象会创建并注册它自己的JobProgressListen