1 需要剖析
1.1 剖析压测对象
1)什么是 ClickHouse 和 Elasticsearch
ClickHouse 是一个真正的列式数据库管理系统(DBMS)。在 ClickHouse 中,数据始终是按列存储的,包含矢量(向量或列块)执行的过程。只有有可能,操作都是基于矢量进行分派的,而不是单个的值,这被称为«矢量化查问执行»,它有利于升高理论的数据处理开销。
Elasticsearch 是一个开源的分布式、RESTful 格调的搜寻和数据分析引擎,它的底层是开源库 Apache Lucene。它能够被这样精确地形容:
一个分布式的实时文档存储,每个字段能够被索引与搜寻
一个分布式实时剖析搜索引擎
能胜任上百个服务节点的扩大,并反对 PB 级别的结构化或者非结构化数据
2)为什么要对他们进行压测
家喻户晓,ClickHouse 在根本场景体现十分优良,性能优于 ES,然而咱们理论的业务查问中有很多是简单的业务查问场景,甚至是大数量的查问,所以为了在双十一业务峰值来到前,确保大促流动峰值业务稳定性,针对 ClickHouse 和 Elasticsearch 在咱们理论业务场景中是否领有优良的抗压能力,通过这次性能压测,探测系统中的性能瓶颈点,进行针对性优化,从而晋升零碎性能。
1.2 制订压测指标
为什么会抉择这个(queryOBBacklogData)接口呢?
1)从复杂度来看,接口(queryOBBacklogData)查问了 5 次,代码如下:
/**
* 切 ck-queryOBBacklogData
* @param queryBO
* @return
*/
public OutboundBacklogRespBO queryOBBacklogDataCKNew(OutboundBacklogQueryBO queryBO) {log.info("queryOBBacklogDataCK 入参:{}", JSON.toJSONString(queryBO));
// 公共条件 - 卡最近十天工夫
String commonStartTime = DateUtils.getTime(DateUtil.format(new Date(), DateUtil.FORMAT_DATE), DateUtils.ELEVEN_AM, 1, -10);
String commonEndTime = DateUtils.getTime(DateUtil.format(new Date(), DateUtil.FORMAT_DATE), DateUtils.ELEVEN_AM, 1, 1);
// 越库信息 - 待越库件数 & 待越库工作数
WmsObCrossDockQueryBo wmsObCrossDockQueryBo = wmsObCrossDockQueryBoBuilder(queryBO,commonStartTime, commonEndTime);
log.info("queryOBBacklogDataCK-wmsObCrossDockQueryBo: {}", JSON.toJSONString(wmsObCrossDockQueryBo));
CompletableFuture<OutboundBacklogRespBO> preCrossDockInfoCF = CompletableFuture.supplyAsync(() -> wmsObCrossDockMapper.preCrossDockInfo(wmsObCrossDockQueryBo), executor);
// 汇合工作信息 - 待调配订单
WmsObAssignOrderQueryBo wmsObAssignOrderQueryBo = wmsObAssignOrderQueryBoBuilder(queryBO, commonStartTime, commonEndTime);
log.info("queryOBBacklogDataCK-wmsObAssignOrderQueryBo: {}", JSON.toJSONString(wmsObAssignOrderQueryBo));
CompletableFuture<Integer> preAssignOrderQtyCF = CompletableFuture.supplyAsync(() -> wmsObAssignOrderMapper.preAssignOrderInfo(wmsObAssignOrderQueryBo), executor);
// 拣货信息 - 待拣货件数 & 待拣货工作数
WmsPickTaskQueryBo wmsPickTaskQueryBo = wmsPickTaskQueryBoBuilder(queryBO, commonStartTime, commonEndTime);
log.info("queryOBBacklogDataCK-wmsPickTaskQueryBo: {}", JSON.toJSONString(wmsPickTaskQueryBo));
CompletableFuture<OutboundBacklogRespBO> prePickingInfoCF = CompletableFuture.supplyAsync(() -> wmsPickTaskMapper.pickTaskInfo(wmsPickTaskQueryBo), executor);
// 分播信息 - 待分播件数 & 待分播工作
WmsCheckTaskDetailQueryBo wmsCheckTaskDetailQueryBo = wmsCheckTaskDetailQueryBoBuilder(queryBO, commonStartTime, commonEndTime);
log.info("queryOBBacklogDataCK-wmsCheckTaskDetailQueryBo: {}", JSON.toJSONString(wmsCheckTaskDetailQueryBo));
CompletableFuture<OutboundBacklogRespBO> preSowInfoCF = CompletableFuture.supplyAsync(() -> wmsCheckTaskDetailMapper.checkTaskDetailInfo(wmsCheckTaskDetailQueryBo), executor);
// 发货信息 - 待发货件数
WmsOrderSkuQueryBo wmsOrderSkuQueryBo = wmsOrderSkuQueryBoBuilder(queryBO, commonStartTime, commonEndTime);
log.info("queryOBBacklogDataCK-wmsOrderSkuQueryBo: {}", JSON.toJSONString(wmsOrderSkuQueryBo));
CompletableFuture<Integer> preDispatchCF = CompletableFuture.supplyAsync(() -> wmsOrderSkuMapper.preDispatchInfo(wmsOrderSkuQueryBo), executor);
return processResult(preCrossDockInfoCF, preAssignOrderQtyCF, prePickingInfoCF, preSowInfoCF, preDispatchCF);
}
2)接口(queryOBBacklogData),总共查问了 5 个表,如下:
wms.wms_ob_cross_dock
wms.wms_ob_assign_order
wms.wms_picking_task.
wms.wms_check_task_detail
wms.wms_order_sku
3)查问的数据量,如下:
select
(ifnull(sum(m.shouldBeCrossedDockQty),
0) -
ifnull(sum(m.satisfiedCrossedDockQty),
0)) as preCrossStockSkuQty,
count(m.docId) as preCrossStockTaskQty
from
wms.wms_ob_cross_dock m final
prewhere
m.createTime >= '2021-12-03 11:00:00'
and m.createTime <= '2021-12-14 11:00:00'
and m.warehouseNo = '279_1'
and m.orderType = '10'
and tenantCode = 'TC90230202'
where
m.deleted = 0
and m.deliveryDestination = '2'
and m.shipmentOrderDeleted = 0
and m.status = 0
从下面 SQL 截图能够看出,查问待越库件数 & 待越库工作数,共读了 720817 行数据
select count(distinct m.orderNo) as preAssignedOrderQty
from wms.wms_ob_assign_order m final
prewhere
m.createTime >= '2021-12-03 11:00:00'
and m.createTime <= '2021-12-14 11:00:00'
and m.warehouseNo = '361_0'
and tenantCode = 'TC90230202'
where m.taskassignStatus = 0
and m.deliveryDestination = 2
and m.stopProductionFlag = 0
and m.deleted = 0
and m.orderType = 10
从下面 SQL 截图能够看出,查问汇合工作信息 - 待调配订单,共读了 153118 行数据
select minus(toInt32(ifnull(sum(m.locateQty), toDecimal64(0, 4))),
toInt32(ifnull(sum(m.pickedQty), toDecimal64(0, 4)))) as prePickingSkuQty,
count(distinct m.taskNo) as prePickingTaskQty
from wms.wms_picking_task m final
prewhere
m.shipmentOrderCreateTime >= '2021-12-03 11:00:00'
and m.shipmentOrderCreateTime <= '2021-12-14 11:00:00'
and m.warehouseNo = '286_1'
and tenantCode = 'TC90230202'
where m.pickingTaskDeleted = 0
and m.deliveryDestination = 2
and m.pickLocalDetailDeleted = 0
and m.shipmentOrderDeleted = 0
and m.orderType = 10
and (m.operateStatus = 0 or m.operateStatus = 1)
从下面 SQL 截图能够看出,查问拣货信息 - 待拣货件数 & 待拣货工作数,共读了 2673536 行数据
select minus(toInt32(ifnull(sum(m.locateQty), toDecimal64(0, 4))),
toInt32(ifnull(sum(m.pickedQty), toDecimal64(0, 4)))) as prePickingSkuQty,
count(distinct m.taskNo) as prePickingTaskQty
from wms.wms_picking_task m final
prewhere
m.shipmentOrderCreateTime >= '2021-12-03 11:00:00'
and m.shipmentOrderCreateTime <= '2021-12-14 11:00:00'
and m.warehouseNo = '279_1'
and tenantCode = 'TC90230202'
where m.pickingTaskDeleted = 0
and m.deliveryDestination = 2
and m.pickLocalDetailDeleted = 0
and m.shipmentOrderDeleted = 0
and m.orderType = 10
and (m.operateStatus = 0 or m.operateStatus = 1)
从下面 SQL 截图能够看出,查问分播信息 - 待分播件数 & 待分播工作,共读了 1448149 行数据
select ifnull(sum(m.unTrackQty), 0) as unTrackQty
from wms.wms_order_sku m final
prewhere
m.shipmentOrderCreateTime >= '2021-12-03 11:00:00'
and m.shipmentOrderCreateTime <= '2021-12-14 11:00:00'
and m.warehouseNo = '280_1'
and m.orderType = '10'
and m.deliveryDestination = '2'
and tenantCode = 'TC90230202'
where m.shipmentOrderDeleted <> '1'
and m.ckDeliveryTaskDeleted <> '1'
and m.ckDeliveryTaskDetailDeleted <> '1'
and m.ckDeliveryTaskStatus in ('1','0','2')
从下面 SQL 截图能够看出,查问发货信息 - 待发货件数,共读了 99591 行数据
2 测试环境筹备
为了尽可能施展性能压测作用,性能压测环境该当尽可能同线上环境统一,所以咱们应用了和线上一样的环境
3 采集工具筹备
监控工具
http://origin.jd.com/:监控 JVM,办法级别监控(提供秒级反对)
http://console.jex.jd.com/:提供异样堆栈监控,火焰图监控、线程堆栈剖析
http://x.devops.jdcloud.com/:反对查看 clickhouse/Elasticsearch 数据库服务每个节点的 cpu 使用率
http://dashboard.fireeye.jdl.cn/:监测应用服务器 cpu 使用率、内存使用率
4 压测执行及后果剖析
4.1 编写压测脚本工具
Forcebot(http://forcebot.jd.com)是专门为开发人员、测试人员提供的性能测试平台,通过编写脚本、配置监控、设置场景、启动工作、实时监控、日志定位、导出报告一系列操作流程来实现性能测试,灵便的脚本配置满足同步、异步、集合点等多种发压模式。
帮忙文档(http://doc.jd.com/forcebot/he…)
4.2 设计压测数据
4.2.1 后期压测中名词解释
DBCP:数据库连接池,是 apache 上的一个 Java 连接池我的项目。DBCP 通过连接池事后同数据库建设一些连贯放在内存中(即连接池中),应用程序须要建设数据库连贯时间接到从接池中申请一个连贯应用,用完后由连接池回收该连贯,从而达到连贯复用,缩小资源耗费的目标。
maxTotal:是连接池中总连贯的最大数量,默认值 8
max_thread:clickhouse 中底层配置,解决 SQL 申请时应用的最大线程数。默认值是 clickhouse 服务器的外围数量。
coordinating:协调节点数,次要作用于申请转发,申请响应解决等轻量级操作
数据节点:次要是存储索引数据的节点,次要对文档进行增删改查操作,聚合操作等。数据节点对 cpu,内存,io 要求较高,在优化的时候须要监控数据节点的状态,当资源不够的时候,须要在集群中增加新的节点
4.2.2 压测数据
clickhouse 数据服务:32C128G6 节点 2 正本
应用服务器:4 核 8G2
maxTotal=16
注:每次压测前,肯定要察看每个数据节点的 cpu 使用率
注:从下面压测过程中,序号 6 -12 能够看出,并发用户数在减少,但 tps 没有幅度变动,查看发现 bigdata dbcp 数据库链接池最大线程数未配置,默认最大线程数是 8,并发用户数减少至 8 当前,clickhouse cpu 稳固在 40%~50% 之间不再减少,应用服务器 CPU 稳固在 25% 左右。
之后咱们调整 maxTotal=50,通过调整 max_thread 不同的值,数据库节点 CPU 使用率放弃在 50% 左右,来查看相应的监测数据指标:应用服务 CPU 使用率、TPS、TP99、并发用户数。
clickhouse 数据节点,CPU 使用率:
Elasticsearch 数据服务:32C128G6 节点 2 正本
应用服务器:4 核 8G2
Elasticsearch 同样放弃数据库服务 CPU 使用率达到(50% 左右),再监控数据指标 tps、tp99
调整指标如下:coordinating 协调节点数、数据节点、poolSize
指标 1:coordinating=2,数据节点 =4,poolSize=400
注:在压测的过程中发现,coordinating 节点的 cpu 使用率达到 51.69%,负载平衡的作用受限,所以协调节点需扩容 2 个节点
指标 2:coordinating=4,数据节点 =5,poolSize=800
注:在压测的过程中,发现 CPU 使用率(数据库)ES 数据节点在 40% 左右的时候,始终上不去,查看日志发现 activeCount 曾经达到 797,须要减少 poolSize 值
指标 3:coordinating=4,数据节点 =5,poolSize=1200
注:压测过程中,发现 coordinating 协调节点还是须要扩容,不能反对当初数据节点 cpu 使用率达到 50%
Elasticsearch 数据节点及协调节点,CPU 使用率:
咱们在压测的过程中发现一些之前在开发过程中没发现的问题,首先 bdcp 数 bigdata 应用服务器,应用的线程池最大线程数为 8 时,成为瓶颈,用户数减少至 8 当前,clickhouse 的 cpu 稳固在 40%~50% 之间不在减少,应用服务器 CPU 稳固在 25% 左右,其次 warehouse 集群协调节点配置低,协调节点 CPU 使用率高,最初是 clickhouse-jdbc JavaCC 解析 sql 效率低。
4.3 后果剖析
4.3.1 测试论断
1)clickhouse 对并发有肯定的反对,并不是不反对高并发,能够通过调整 max_thread 进步并发
max_thread=32 时,反对最大 TPS 是 37,相应 TP99 是 122
max_thread= 2 时,反对最大 TPS 是 66,相应 TP99 是 155
max_thread= 1 时,反对最大 TPS 是 86,相应 TP99 是 206
2)在并发方面 Elasticsearch 比 clickhouse 反对的更好,然而相应的响应速度慢很多
Elasticsearch:对应的 TPS 是 192,TP99 是 3050
clickhouse:对应的 TPS 是 86,TP99 是 206
综合考量,咱们认为 clickhouse 足以撑持咱们的业务诉求
4.3.2 优化倡议
对 ES 协调节点进行扩容
bigdata 利用线程池最大线程数调高至 200
bigdata 利用 dbcp 线程池 maxTotal 设置成 50
读取配置文件工具类减少内存缓存
作者:潘雪艳