原本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 corePoolSize | 4 corePoolSize | 6 corePoolSize | 8 corePoolSize | 10 corePoolSize | 12 corePoolSize | |
---|---|---|---|---|---|---|---|
1000 Plans 10000 row 16 columns | 1952 | 1906 | 1742 | 1608 | 1736 | 1670 | 1641 |
由于测试设备的可利用总线程数为12,我们可以发现当核心线程数为Runtime.getRuntime().availableProcessors()/2时,执行速度最快。
同时需要考虑的是,如果insertTablet单次执行速度过快时,可能会导致频繁的线程之间切换也会浪费一定的时间,因此我们也要测试出plan的大小,这样线程池的速度才会超过串行的速度,因此我们又做了以下测试:
串行 | 6 corePoolSize | |
---|---|---|
1000Plans 10000row 8 columns | 710 | 809 |
1000Plans 10000row 10 columns | 1018 | 960 |
1000Plans 10000row 12 columns | 1912 | 1717 |
我们可以发现当10 columns的时候,这个时候并行已经超过了串行的速度。
同时我们还需要考虑同一批plan中不同storage group的数量,如果都是相同的sg,底层会被上锁,实际也会退化成串行,如果sg数量过多的话,可能会无法分配堆外内存,导致NPE。
因此我们可以得到开启多线程的条件:
- sg的数量>=2并且sg的数量<=官方推荐的sg数量(cpu线程数的两倍)
- 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