接上一篇文章,LiveListenerBus事件总线分发的event,一个非常重要的目标就是存入AppStatusListener,SQLAppStatusListener内部的kvstore: ElementTrackingStore,用于Spark UI展示 :
- Spark UI中Job、Stage、Task页面,调用AppStatusStore提供的方法,读取kvstore中存储的rdd任务相关信息。
- Spark UI中SQL页面,调用SQLAppStatusStore提供的方法,读取kvstore中存储的SparkPlan物理计划(SQL真实执行流程)相关信息。
一、KVStore定义及实现
KVStore是一个特质,定义了数据的读、写、删除、count()计算总数等方法,其两个重要的实现是InMemoryStore和ElementTrackingStore
1、InMemoryStore内存方式存储
- InMemoryStore内部定义了数据结构:
ConcurrentMap<Class<?>, InstanceList> data = new ConcurrentHashMap<>() - 上述data是围绕记录的class类型进行分类存储。
InstanceList内部保存了某个对应class数据的多条信息,例如UI默认展示的1000个Stage信息,其调用顺序AppStatusStore.stageList(xxx) —> store.view(classOf[StageDataWrapper]) - store.view(xxx)方法返回的是KVStoreView的子类InMemoryView(),可以对InstanceList内部的数据进行排序,也就是我们在UI中看到的最新Stage信息总在最前
- 在调用InMemoryView iterator()方法时,会先将内部elements数据进行排序,并根据设置的first、last、skip信息对sorted数据进行过滤,最后返回一个InMemoryIterator
public class InMemoryStore implements KVStore {
...
private ConcurrentMap<Class<?>, InstanceList> data = new ConcurrentHashMap<>();
// 统计某一class数据总量,例如store.count(classOf[SQLExecutionUIData])统计运行的SQL总量
@Override
public long count(Class<?> type) {
InstanceList list = data.get(type);
return list != null ? list.size() : 0;
}
// 某一对象的数据量,例如store.count(classOf[TaskDataWrapper], "stage", Array(stageId, stageAttemptId))获取某个stage的task总数
@Override
public long count(Class<?> type, String index, Object indexedValue) throws Exception {
InstanceList list = data.get(type);
int count = 0;
Object comparable = asKey(indexedValue);
KVTypeInfo.Accessor accessor = list.getIndexAccessor(index);
for (Object o : view(type)) {
if (Objects.equal(comparable, asKey(accessor.get(o)))) {
count++;
}
}
return count;
}
// 获取某一class指定key数据,例如:store.read(classOf[SQLExecutionUIData], executionId)获取指定executionId的SQL运行描述detail
@Override
public <T> T read(Class<T> klass, Object naturalKey) {
InstanceList list = data.get(klass);
Object value = list != null ? list.get(naturalKey) : null;
if (value == null) {
throw new NoSuchElementException();
}
return klass.cast(value);
}
// 写入一条数据,先获取数据的class,不存在则先创建class对应的数据列表Ins