鲲鹏社区首页
中文
注册
开发者
使用Java-Perf进行性能调优提高tps

使用Java-Perf进行性能调优提高tps

性能调优

发表于 2025/12/05

0

背景

XXXX项目在线填报用例 tps 为 3.6/sec,不符合预期,希望进行调优。

在线填报用例分为预览 和 上报两个接口,其中预览接口的tps远大于 3.6,

瓶颈是上报接口。

50并发是上报接口tps最优的并发数, tps 为 5.6/sec,均耗时为 8.9s

单并发上报接口 tps 为 1/sec,平均耗时为 1s

并发高的情况下,上报接口耗时增多了将近8倍,但是 tps 提升的不多。各项系统资源使用率都不高,无瓶颈。

接下来的调优重点是分析接口耗时大幅度增多的原因,降低耗时,从而提升tps

1、采集热点火焰图 &锁火焰图

热点火焰图

热点函数 OnlineFillController.largeAmountReport 是报送接口的入口函数,

Jvm内部代码编译操作以及GC相关操作也属于热点操作


接下来可通过java调优工具分析下对应程序的线程状态、GC执行情况,对 largeAmountReport 进行插桩,具体分析其调用链的耗时。


锁火焰图



大部分锁是日志打印相关的锁,可通过java调优工具分析线程的锁情况。

2、分析GC活动

50并发

1并发

分析java工具采集的GC 活动数据,GC频率比较均匀,垃圾回收耗时也不高,耗时也没有随着并发的增高也明显变大。

3、分析线程状态&线程锁竞争情况

50并发

通过java工具在线分析-概览发现,在50并发压测下,程序80% 的线程会处于等待状态

锁分析

通过锁图和统计分析,60个业务线程中有42个线程会因为竞争同一把锁而处于等待状态。

根据调用栈发现这把锁处于从druid数据库连接池中获取数据库连接的操作中。


可通过 java工具抓取应用的SQL执行情况;

分析 org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection 获取数据库连接的函数在低并发和高并发情况下的耗时。

4、分析SQL语句执行情况

1并发压测

50并发压测

通过java工具采集SQL执行情况,经分析耗时最长的一个SQL查询语句,50并发和单并发对比,耗时增加了0.4s 左右,其他SQL语句耗时基本没变。

对于1s 9s的报送接口耗时倍增情况,执行SQL语句增加的耗时只能占小部分。


5、关键函数调用链耗时分析

DataSourceUtils.fetchConnection 函数

1并发

50并发

获取数据库连接操作的耗时,随着并发的提高耗时会明显增大,0.001 ms -> 589ms



该操作内部涉及锁竞争,说明随着并发的提高,锁竞争也会越激烈。


通过第四步的采集数据得知一次报送操纵会涉及9 SQL语句的执行。

我们假定一次报送每条SQL执行一次,那么就会有从数据库连接池中拿9次数据库连接的动作,我们以1 并发和 50并发为例,(589-0.001* 9 / 1000 = 5.3s

50并发情况下,一次报送操作,光在获取数据库连接的耗时上就多了5.3s

5.3s 对于整体的耗时占比比重也较大,约为 58%


降低获取数据库连接的耗时,是个重要的调优方向。


分析数据库连接池参数

通过采集的数据得知,该应用druid数据库连接池的最大连接为8,它代表这个连接池最多创建8个数据库连接供应用使用。

那么在并发50的情况下,最多只有8个线程能拿到数据库连接去跟数据库做交互,其他的线程都得排队等待。这一点能跟第三步的分析对得上。

适当调高这个数据库连接数的上限,能同时拿到数据库连接的线程就会变多,排队等待的线程就会减少。理论上获取数据库连接的操作耗时也会响应减少。

接下来做验证。


6、调高数据库连接池的最大连接数进行验证

启动参数调整数据库连接数

通过启动参数-Dspring.datasource.druid.max-active 调整druid数据库连接池的最大连接数

压测

经过不断调整并发数和数据库连接池数作压测验证,60 并发 60 数据库连接数的组合下tps最佳,tps 5.6 / sec 提高到 18 / sec,耗时也从 8.9s降低到3.2s

这个效果是很明显的。


线程状态

等待状态的线程比例从80% 降低到 44%

锁分析


31个业务线程因等待获取锁而处于阻塞或等待状态,占比为50%

但是等待锁变为了两把,而且都是跟lockback插件打印日志有关,不再是之前的获取数据库连接相关的锁


关键函数耗时

DataSourceUtils-fetchConnection:


获取数据库连接耗时从589ms 降低到 0.003ms,接近单并发的耗时。

SQL语句耗时

60并发 60 数据库连接:

60并发 8 数据库连接:

SQL语句的耗时比50并发的耗时明显增多

这不难理解,数据库连接变多,那么跟数据库的操作就会变得更频繁,数据的压力就会变大,

相关SQL执行时间变长也是比较正常的。

关键进程资源变化

报送业务进程

50并发 8 数据库连接:


60并发 60 数据库连接:

报送进程 cpu使用率从 35% 升高到94%

Mysql进程

50并发 8 数据库连接:

60并发 60 数据库连接:

mysql进程 cpu使用率 763% 升高到 2000%,压力明显增加

总结

通过第六步的验证结果及相关指标的变化,可以得出调高druid数据库连接池的最大连接数,

在并发高的情况下减轻业务线程获取数据库连接的压力,规避排队等待获取数据库连接的现象。

调优方案&优化结果

调高druid数据库连接池的最大连接数到60


报送接口tps5.6 / sec 提高到 18 / sec,耗时也从 8.9s降低到3.2s


在线填报用例 tps3.6 / sec 提高到 18 / sec


案例总结

1、  针对吞吐量调优(tpsqps等),如果随着并发的提高,发现吞吐量明线不是线性升高的趋势,可以怀疑是不是业务中有同步锁的操作。

2、  性能调优一定要从问题最大的点出发,这样调优后收益往往是最大的。

本案例来讲,报送接口单并发下耗时为1stps 1 / sec,假设报送逻辑是并行的,互不影响,在理想(资源足够并且无其他干扰因素)情况下,5并发tps应该可以到5/ sec10并发tps应该可以到10/ sec。但是经过压测50 并发 tps 最高只有5.6 / sec,缩水有点严重,可以怀疑是不是存在同步阻塞的操作,让并行变成了串行或者 其他的资源瓶颈导致的。还有一点 耗时 1s 增加到 8.9s,增大比例有点多。

从上述现象看,调优重点是 分析下锁看是否存在同步阻塞操作;分析下耗时增大明显的原因;分析是否出现资源瓶颈。







本页内容