spark 2.4.0源码分析--(二)AppStatusListener与SQLAppStatusListener事件响应及存储

本文深入探讨Spark 2.4.0中AppStatusListener和SQLAppStatusListener的事件响应及存储策略。文章详细分析了KVStore的InMemoryStore和ElementTrackingStore实现,特别是如何限制存储条目并删除冗余数据。此外,还介绍了AppStatusStore如何与Spark UI交互,提供Job、Stage、Task和SQL页面的数据。同时,文章指出SQLAppStatusListener存在的内存泄漏问题及其解决方案。

接上一篇文章,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对应的数据列表InstanceList
  @Override
  public void write(Object value) throws Exception {
    InstanceList list = data.computeIfAbsent(value.getClass(), key -> {
      try {
        return new InstanceList(key);
      } catch (Exception e) {
        throw Throwables.propagate(e);
      }
    });
    list.put(value);
  }

  //删除一条数据,例如kvstore.delete(t.getClass(), t.taskId)
  @Override
  public void delete(Class<?> type, Object naturalKey) {
    InstanceList list = data.get(type);
    if (list != null) {
      list.delete(naturalKey);
    }
  }

  // 查看某个类对应的全部数据,返回InMemoryView排序后迭代器
  @Override
  public <T> KVStoreView<T> view(Class<T> type){
    InstanceList list = data.get(type);
    return list != null ? list.view(type)
      : new InMemoryView<>(type, Collections.<T>emptyList(), null);
  }
}

2、ElementTrackingStore中检测超过指定条目的数据,并删除

由ElementTrackingStore的代码可知,其主要代理其内部store: InMemorySotre的方法,并提供数据删除功能

private[spark] class ElementTrackingStore(store: 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值