StarRocks FE leader节点CPU使用率周期性的忽高忽低问题分析

背景

本文基于 StarRocks 3.3.5

最近在做一些 StarRocks 相关的指标监控的时候,看到了FE master的CPU使用率相对其他FE节点是比较高的,且 呈现周期性的变化(周期为8分钟),

于此同时FE master节点的GC频率相对于其他节点高出很多倍,于是我们利用arthas采集了大约15分钟CPU的火焰图。如下:

对应的FE master节点的CPU使用率的变化如下图:

FE 其他节点的CPU使用率的变化如下图:

对应的FE master节点的Young GC的变化如下图:

FE 其他节点的Young GC变化如下图:

结论

CPU使用率高的主要集中在三个点:

  1. StatisticAutoCollector(占用28%)
  2. MemoryUsageTracker (占用9%)
  3. JVM GC(占用57%)
    因为在我们的场景下,实时写入的任务比较多,且写入的是分区表(由于业务的场景问题,会更新以前分区的数据),所以会导致 StatisticAutoCollector 进行相关统计信息的收集,而这个统计信息的收集,会触发System.gc操作,从而导致FE master节点的 gc频率比其他节点高很多。

分析

StatisticAutoCollector

StatisticAutoCollector 这个类只有在FE Master才会被调用,且调用的频率为statistic_collect_interval_sec,也就是5分钟。

该线路数据流为:

StatisticAutoCollector.runAfterCatalogReady
    ||
    \/
runJobs
    ||
    \/
StatisticExecutor.collectStatistics
    ||
    \/
FullStatisticsCollectJob.collect
    ||
    \/
collectStatisticSync
    ||
    \/
StmtExecutor.executeStatisticDQL
    ||
    \/
StmtExecutor.executeDQL
    ||
    \/
StatementPlanner.plan //走到 生成计划
    ||
    \/
createQueryPlanWithReTry
    ||
    \/
collectOriginalOlapTables
    ||
    \/
OlapTable.copyOnlyForQuery
    ||
    \/
partitionInfo.clone()

partitionInfo.clone() 会初始化HashMap来复制partiiton的信息:

 protected Object clone()  {
        try {
            PartitionInfo p = (PartitionInfo) super.clone();
            p.type = this.type;
            p.idToDataProperty = new HashMap<>(this.idToDataProperty);
            p.idToReplicationNum = new HashMap<>(this.idToReplicationNum);
            p.isMultiColumnPartition = this.isMultiColumnPartition;
            p.idToInMemory = new HashMap<>(this.idToInMemory);
            p.idToTabletType = new HashMap<>(this.idToTabletType);
            p.idToStorageCacheInfo = new HashMap<>(this.idToStorageCacheInfo);
            return p;
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

所以说在这种要收集的分区信息很多的情况下,HashMap的初始化,就很消耗CPU。

再者,在collectStatistics 之前会通过 StatisticsCollectJobFactory.buildStatisticsCollectJob 这个方法计算出要收集的 FullStatisticsCollectJob ,这里会通过执行select $quoteColumnName as column_key from $dbName.$tableName partition $partitionName这种方法收集每个分区中某些字段的信息,这里后续会详细说

MemoryUsageTracker

StatisticAutoCollector 这个类只有在FE Master才会被调用,且调用的频率为 memory_tracker_interval_seconds ,也就是1分钟。

该类的数据流为:

MemoryUsageTracker.runAfterCatalogReady
    ||
    \/
MemoryUsageTracker.trackMemory
    ||
    \/
MemoryTrackable.estimateSize
    ||
    \/
SizeEstimator.estimate

这里会根据初始化方法initMemoryTracker涉及到的对象进行内存的评估,具体的对象如下:

 private void initMemoryTracker() {
        GlobalStateMgr currentState = GlobalStateMgr.getCurrentState();

        registerMemoryTracker("Load", currentState.getLoadMgr());
        registerMemoryTracker("Load", currentState.getRoutineLoadMgr());
        registerMemoryTracker("Load", currentState.getStreamLoadMgr());
        registerMemoryTracker("Load", currentState.getInsertOverwriteJobMgr());

        registerMemoryTracker("Compaction", currentState.getCompactionMgr());
        registerMemoryTracker("Export", currentState.getExportMgr());
        registerMemoryTracker("Delete", currentState.getDeleteMgr());
        registerMemoryTracker("Transaction", currentState.getGlobalTransactionMgr());
        registerMemoryTracker("Backup", currentState.getBackupHandler());
        registerMemoryTracker("Task", currentState.getTaskManager());
        registerMemoryTracker("Task", currentState.getTaskManager().getTaskRunManager());
        registerMemoryTracker("TabletInvertedIndex", currentState.getTabletInvertedIndex());
        registerMemoryTracker("LocalMetastore", currentState.getLocalMetastore());

        registerMemoryTracker("Query", new QueryTracker());
        registerMemoryTracker("Profile", ProfileManager.getInstance());
        registerMemoryTracker("Agent", new AgentTaskTracker());

        QeProcessor qeProcessor = QeProcessorImpl.INSTANCE;
        if (qeProcessor instanceof QeProcessorImpl) {
            registerMemoryTracker("Coordinator", (QeProcessorImpl) qeProcessor);
        }

        IDictManager dictManager = IDictManager.getInstance();
        if (dictManager instanceof CacheDictManager) {
            registerMemoryTracker("Dict", (CacheDictManager) dictManager);
        }

        memoryMXBean = ManagementFactory.getMemoryMXBean();

        LOG.info("Memory usage tracker init success");

        initialize = true;
    }

这里会对里面涉及到的所有对象进行内存的评估,用来后续的内存使用指标显示。

JVM GC

这个方法是在每个SQL执行完后就会触发的,具体的数据流为:

  StatisticAutoCollector.runJobs
     ||
     \/
  StatisticExecutor.collectStatistics
     ||
     \/
  FullStatisticsCollectJob.collect
     ||
     \/
  FullStatisticsCollectJob.collectStatisticSync 
     ||
     \/
  flushInsertStatisticsData 
     ||
     \/
  StmtExecutor.execute() 
     ||
     \/
  GlobalStateMgr.getCurrentState().getMetadataMgr().removeQueryMetadata();
     ||
     \/
  queryMetadatas.metadatas.values().forEach(ConnectorMetadata::clear)
     ||
     \/
  LocalMetaStore.clear ->  System.gc()

当然这也只是该 StatisticAutoCollector 定时的触发的,还有如果有查询SQL的话,也会进行触发。具体看 StmtExecutor.execute方法:

   public void execute() throws Exception {
   ...
   try {
   ...
   } finally {
      GlobalStateMgr.getCurrentState().getMetadataMgr().removeQueryMetadata();
      if (context.getState().isError() && coord != null) {
          coord.cancel(PPlanFragmentCancelReason.INTERNAL_ERROR, context.getState().getErrorMessage());
      }

      if (parsedStmt != null && parsedStmt.isExistQueryScopeHint()) {
          clearQueryScopeHintContext();
      }

      // restore session variable in connect context
      context.setSessionVariable(sessionVariableBackup);
     }
   }
相关推荐
猎人everest36 分钟前
SpringBoot应用开发入门
java·spring boot·后端
山猪打不过家猪3 小时前
ASP.NET Core Clean Architecture
java·数据库·asp.net
AllowM3 小时前
【LeetCode Hot100】除自身以外数组的乘积|左右乘积列表,Java实现!图解+代码,小白也能秒懂!
java·算法·leetcode
Biomamba生信基地3 小时前
两天入门R语言,周末开讲
开发语言·r语言·生信
RAN_PAND3 小时前
STL介绍1:vector、pair、string、queue、map
开发语言·c++·算法
Bio Coder3 小时前
R语言安装生物信息数据库包
开发语言·数据库·r语言
Tiger Z3 小时前
R 语言科研绘图第 27 期 --- 密度图-分组
开发语言·程序人生·r语言·贴图
不会Hello World的小苗3 小时前
Java——列表(List)
java·python·list
二十七剑4 小时前
jvm中各个参数的理解
java·jvm