一句话总结
在金融级系统里面,性能测试工具需要比系统本身更加健壮。
原生JUC线程池+原子类实现高性能压测
业务痛点和需求
在金融交易系统中,每秒需要处理数万笔订单交易请求,交易系统的TPS直接关系到机构客户的收益,我们团队在升级核心交易引擎的时候,发现现有的JMeter工具存在以下的痛点:
- 定制化程度不够:无法灵活的采集特定的业务指标,比如委托响应延迟分别
- 资源消耗大: 万级并发时,JMeter本身成为性能瓶颈。https://developer.aliyun.com/article/1195540 这是一些优化的场景
- 统计粒度较粗: 缺少细粒度的成功&失败的计数
- 动态调整难:无法实时调整并发压力模型
在此基础上,自研的压测工具需要满足以下的目标:
- 支持5w+ QPS
- 毫秒级别的统计精度
- 精准控制并发数
技术挑战和破局思路
维度 | 自研方案的突破点 |
---|---|
精准控制并发数 | prestartAllCoreThreads预热机制+SynchronousQueue严格实时传递请求+无缓冲设计 |
资源竞争 | CAS+AtomicLong等原子类无锁计数 |
结果聚合 | LongAdder分片计数 |
关键实现难点 :
精准压力模型构建(严格控制并发)
- 严格控制并发:corePoolSize=maximumPoolSize使得线程动态失效,确保线程恒定
- 零容忍延迟:SynchronousQueue+0秒keepAlive实现请求即时响应或失败
- 自我保护机制:CallerRunsPolicy防止压测工具自身过载,确保任务100%执行,保证数据的准确性
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
cocurrency,
cocurrency,
0L,
TimeUnit.MICROSECONDS,
new SynchronousQueue<>(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
threadPoolExecutor.prestartAllCoreThreads();
这样的配置是为了在压测时精确控制并发线程数,避免任务队列缓冲带来的延迟,提前预热线程以减少启动开销,并通过拒绝策略确保任务不被丢弃,从而准确测量系统在高并发下的表现。
注意:这种精准控制对于资源利用率有一定的消耗。
原子类+CAS无锁化极值统计
比如在计算衍生指标,采用原子类和CAS实现
测试结果
不带延迟的请求10w
压测结果对比
指标 | JMeter | 自研压测工具类 |
---|---|---|
最大QPS | 2w左右 | 5w |
优化方向
维度 | 问题 | 优化思路 |
---|---|---|
成功次数的计算 | 在高并发情况下,可能会有大量线程在循环中重试,尤其是在最小值被频繁更新的时候。例如,当大量请求的延迟都很低时,每个线程都会尝试更新最小值,导致CAS竞争激烈,影响性能 | 使用LongAddr计算 |
✅优化方案:successReqeuests使用LongAdder计数
LongAdder successReqeuests = new LongAdder();
压测后对比
10w不带延迟的
指标 | JMeter | 自研压测工具类V1 | 自研压测工具类V2 |
---|---|---|---|
最大QPS | 2w左右 | 5.0w | 5.2w+ |