乐于分享
好东西不私藏

AI写代码——Java + Spring Boot 代码-->performance benchmark

AI写代码——Java + Spring Boot 代码-->performance benchmark

现在已经确认:

  • sleep_test提交成功

  • 状态查询成功

  • 最终是 SUCCESS

  • 开始时间到结束时间大约 5 秒

这说明:

白名单 + 参数绑定 + 慢查询模板 也已经跑通了。

也就是说,当前最严重的那个问题已经被修掉了:

  • 以前:前端直接传 SQL,存在明显 SQL 注入风险

  • 现在:前端只能传 queryCode + params,后端只执行白名单模板


完成最关键的改造:

  • 原始 SQL 入参已移除

  • 改成 queryCode + params

  • 白名单模板服务已接入

  • 参数绑定已接入

  • 普通查询跑通

  • 慢查询跑通

这意味着:

SQL 注入这个最低级、最明显的问题,第一轮已经处理完了。

进入 performance benchmark

开始正式做性能压测

而且现在压测才有意义,因为接口模型已经是安全版本了。


先安装 k6。在终端执行:brew install k6

装完后检查:k6 version

好,k6已经装好了。

  • Spring Boot 服务在第一个终端里跑着

  • 第二个终端里 k6 version已经正常

  • 可以正式开始做 benchmark

下一步:先建性能测试脚本目录

执行:

cd /Users/edmond/01_Projects/async-query-demomkdir -p performancecd performance

然后我们先只建第一个脚本:普通查询并发压测

然后检查:

cat submit-fast.js

submit-fast.js已经建好了,下一步直接跑第一次压测。

当前这个 performance 终端里执行:

k6 run submit-fast.js

压测已经正常跑起来了。当前这几行说明的是:

  • k6 run submit-fast.js已经启动

  • 场景识别正常

  • 最大并发用户数是 10 VUs

  • 总测试时长是 2 分钟

  • 现在运行到 7.8 秒

  • 当前活跃用户 2/10

  • 已完成迭代 5 次

  • 没有中断

脚本没问题,服务也没挂,benchmark 正在正常执行中。

第一轮 benchmark 跑完了,而且结果很干净。

阈值检查

  • http_req_failed < 1%→ 实际 0.00%

  • p(95) < 1000ms→ 实际 27.57ms

    说明在当前这档压测下:

    • POST /api/query-jobs提交接口稳定

    • queryCode + params新版本没带来明显性能问题

    • 线程池和数据库在这个压力下很轻松

    • 普通查询场景下,系统响应很快

下一步:做慢查询并发压测

slow query benchmark

submit-slow.js建好了,现在直接跑第二轮慢查询压测。

在当前这个 performance终端里执行:

k6 run submit-slow.js

是 failed,现在能确定的事

不是脚本问题,也不是 k6 问题。

是你的服务在 慢查询并发提交场景下,大量请求没能成功创建任务

关键数据还是一样:

  • 总请求:1326

  • 成功:394

  • 失败:932

  • 失败率:70.28%

  • P95:17.26ms

这说明:

请求不是“慢死了”,而是很快被拒绝了

也就是典型的:

  • 异步线程池满了

  • 队列满了

  • 提交任务时直接失败

你现在的配置只有:

  • corePoolSize = 4

  • maxPoolSize = 8

  • queueCapacity = 100

而每个 sleep_test要占 5 秒,10 个 VU 持续提交,顶满是很正常的。


直接进入下一步,先不要分析太多,先扩容线程池再复测

扩容 AsyncConfig.java

好,继续下一步。把 AsyncConfig.java改成:

  • corePoolSize = 8

  • maxPoolSize = 16

  • queueCapacity = 500

1)在当前终端重新编译

执行:

cd /Users/edmond/01_Projects/async-query-demomvn clean package

2)去第一个 Spring Boot 终端端重新启动

执行:

cd /Users/edmond/01_Projects/async-query-demojava -jar target/async-query-demo-1.0.0.jar

3)回到第二个终端重跑慢查询压测

执行:

cd /Users/edmond/01_Projects/async-query-demo/performancek6 run submit-slow.js

还是 failed,但这次比上一次明显改善了。

上一轮

  • 失败率:70.28%

  • P95:17.26ms

说明当时是大量请求被快速拒绝

这次

  • 失败率:10.14%

  • P95:2.24s

  • 平均响应:439.77ms

说明现在已经不是“瞬间大量拒绝”了,而是:

线程池扩容后,系统能接住更多慢任务,但开始出现明显排队和阻塞,仍然有一部分请求失败。

扩容后:

  • 成功请求从 394提高到 841

  • 失败请求从 932降到 95

  • 失败率从 70%降到 10%

这证明一件事:

瓶颈方向判断是对的,线程池/队列容量确实是主要问题之一。

但同时又出现了新现象:

  • P95 从十几毫秒变成 2.24 秒

  • 最大响应到了 6.7 秒

这说明:

请求不再是直接被拒绝,而是开始等待资源。

所以现在的瓶颈已经从“立刻拒绝”变成了“排队太久 + 部分超时/失败”。


扩容有效,系统承载能力明显上去了。

现在最可能还差哪两块

1. 数据库连接池

你还没显式调 Hikari 连接池。

现在线程池已经到:

  • core = 8

  • max = 16

但数据库连接池可能还是默认值,慢查询会长期占连接。

2. 压测场景本身很重

  • 每个任务 pg_sleep(5)

  • 持续 10 VUs

  • 跑 3 分半

这对单机本地:

  • Java 应用

  • PostgreSQL

  • k6

都在同一台 Mac 上跑,其实已经不轻了。

我看了,这次结果变差了

两轮慢查询压测对比

上一轮

  • 失败率:10.14%

  • P95:2.24s

  • 特征:很多请求能接住,但开始排队,延迟变高

这一轮(加大 Hikari 连接池后)

  • 失败率:29.64%

  • P95:12.9ms

  • 特征:请求返回更快了,但更多请求被快速拒绝了


这次不是数据库连接池优化成功,而是出现了更明确的现象:

请求被更早、更快地拒绝了。

因为:

  • http_req_duration很低,P95 只有 12.9ms

  • 但失败率高达 29.64%

这不是“系统慢”,而是“系统没接进去”。


现在更像是:

1. 异步线程池 / 任务队列仍然是主要瓶颈

  • corePoolSize = 8

  • maxPoolSize = 16

  • queueCapacity = 500

但对 pg_sleep(5)这种任务,10 个 VU 持续 3 分半不断提交,还是很容易把后台处理能力顶满。

2. 连接池扩容没有解决核心问题

Hikari 变大后,数据库连接更充足了,但这不等于后台任务吞吐就一定提升。

真正限制提交成功率的,仍然更像是:

  • 异步任务接纳能力

  • 线程池拒绝策略

  • 队列消化速度


已经验证出一个很有价值的事实:

慢查询并发场景下,系统的主要瓶颈不在 HTTP 层,也不主要在 JDBC 连接池,而在异步任务处理容量。

这其实是 benchmark 的有效结论。


先改 submit-slow.js,把场景改成只到 5 VUs

stages: [  { duration: '30s', target: 3 },  { duration: '1m', target: 3 },  { duration: '30s', target: 5 },  { duration: '1m', target: 5 },  { duration: '30s', target: 0 },],

做一个保守基线测试

接着运行:

cd /Users/edmond/01_Projects/async-query-demo/performancek6 run submit-slow.js

这轮 5 VUs 基线测试结果:通过

关键指标

  • 总请求数:699

  • 成功率:100%

  • 失败率:0%

  • 平均响应时间:9.37 ms

  • P95:18.49 ms

  • 最大响应时间:38.77 ms

  • 吞吐量:3.33 req/s

阈值检查都通过了:

  • http_req_failed < 5%→ 实际 0.00%

  • p(95) < 1500ms→ 实际 18.49ms


这次结果非常有价值:

当前单机环境下,这套异步查询服务在慢查询场景(5 秒任务)下,5 VUs 压力可以稳定承载。

也就是说:

  • 5 VUs 是你现在这台机器 + 这套配置下的安全基线

  • 之前 10 VUs 失败,不代表系统完全不行

  • 而是说明它的稳定承载区间大概在 5 VUs 左右,再往上就开始明显掉成功率


普通查询场景

  • 10 VUs:通过

  • 失败率 0%

  • P95 很低

慢查询场景

  • 10 VUs:失败

  • 主要表现为任务接纳能力不足

慢查询基线场景

  • 5 VUs:通过

  • 失败率 0%

  • P95 很低

  • 可作为当前版本的稳定基线


场景:慢查询并发提交(sleep_test)压测档位:5 VUs持续时间:3分30秒总请求数:699成功率:100%失败率:0%平均响应时间:9.37msP95:18.49ms最大响应时间:38.77ms吞吐量:3.33 req/s结论:通过1. 记一份性能结果表,把这几轮结果整理成对比:
  • 普通查询 10 VUs:通过

  • 慢查询 10 VUs:失败

  • 慢查询 5 VUs:通过

2. 再做一个混合场景也就是:

  • 提交任务

  • 查状态

  • 查结果

一起压一下,补一个更像真实使用的 benchmark


混合场景压测也通过了,而且结果很好。

这轮 mixed.js 结果通过

关键指标

  • 总请求数:1497

  • 总迭代数:499

  • 成功率:100%

  • 失败率:0%

  • 平均响应时间:5.71 ms

  • P95:9.42 ms

  • 最大响应时间:28.79 ms

  • 吞吐量:7.11 req/s

4 个检查全部通过:

  • submit status is 200

  • submit response has taskId

  • status query is 200

  • result query is 200


说明在当前这套配置下,更接近真实使用方式的混合场景是稳定的

  • 提交任务

  • 查状态

  • 查结果

同时进行时,系统表现很稳,响应也很快。


稳定通过的场景

  1. 普通查询并发提交:10 VUs

  2. 慢查询基线场景:5 VUs

  3. 混合场景:5 VUs

不稳定的场景

  1. 慢查询 10 VUs 持续并发提交


性能结果已经有:

  • 普通查询 benchmark

  • 慢查询 benchmark

  • 慢查询基线 benchmark

  • 混合场景 benchmark

  • 结果汇总文档

足够形成一份完整的第一版性能测试材料。