原本insertTablets函数会循环串行执行insertTablet函数,如果采用线程池的话,可能会加快执行速度。

    for (int i = 0; i < insertMultiTabletPlan.getInsertTabletPlanList().size(); i++) {
      if (insertMultiTabletPlan.getResults().containsKey(i)
          || insertMultiTabletPlan.isExecuted(i)) {
        continue;
      }
      try {
        insertTablet(insertMultiTabletPlan.getInsertTabletPlanList().get(i));
      } catch (QueryProcessException e) {
        insertMultiTabletPlan
            .getResults()
            .put(i, RpcUtils.getStatus(e.getErrorCode(), e.getMessage()));
      }
    }

因此为了验证这个猜想,做了以下的测试:

首先我们把row设置为10000,因为默认的最大值就是10000,并设置plan的个数为1000,column为16,分别以串行,不同的线程池核心线程数进行测试。

测试结果如下表所示:


串行2 corePoolSize4 corePoolSize6 corePoolSize8 corePoolSize10 corePoolSize12 corePoolSize
1000 Plans 10000 row 16 columns1952190617421608173616701641


由于测试设备的可利用总线程数为12,我们可以发现当核心线程数为Runtime.getRuntime().availableProcessors()/2时,执行速度最快。

同时需要考虑的是,如果insertTablet单次执行速度过快时,可能会导致频繁的线程之间切换也会浪费一定的时间,因此我们也要测试出plan的大小,这样线程池的速度才会超过串行的速度,因此我们又做了以下测试:


串行6 corePoolSize
1000Plans 10000row 8 columns710809
1000Plans 10000row 10 columns1018960
1000Plans 10000row 12 columns19121717

我们可以发现当10 columns的时候,这个时候并行已经超过了串行的速度。 

同时我们还需要考虑同一批plan中不同storage group的数量,如果都是相同的sg,底层会被上锁,实际也会退化成串行,如果sg数量过多的话,可能会无法分配堆外内存,导致NPE。

因此我们可以得到开启多线程的条件:

  1. sg的数量>=2并且sg的数量<=官方推荐的sg数量(cpu线程数的两倍)
  2. columns >=10

同时线程池的大小设置为min(不同storage group的数量,availableProcessors()/2)

测试设备

MacBook Pro (16-inch, 2019)

2.6 GHz 6-core processor Core i7

16 GB 2667 MHz DDR4

  • No labels