jmh不能用于测算qps,因其专为方法级微基准测试设计,通过fork隔离jvm、规避gc/jit干扰,而qps是系统级指标,需在真实并发、i/o、线程调度等负载下用jmeter等压测工具测量。

不能用 System.nanoTime() 配合 JMH 测算 QPS。
QPS 和微基准测试是两类问题
QPS(Queries Per Second)是系统级吞吐量指标,反映的是在并发请求、网络 I/O、线程调度、连接池、GC 压力等真实负载下,服务每秒能成功处理多少请求。它天然依赖外部环境,必须用压测工具(如 JMeter、Gatling 或自研压测框架)模拟真实调用链路。
JMH 是微基准测试工具,专为测量单个 Java 方法的纳秒/微秒级开销而设计。它强制隔离 JIT、GC、CPU 频率波动等干扰,甚至每个测试都 fork 一个干净 JVM 进程——这恰恰与 QPS 所需的“共享资源、持续负载、可观测瓶颈”完全背道而驰。
JMH 里测不到 QPS 的根本原因
-
无并发模型:JMH 的
@Threads只控制同一线程内并行执行的 benchmark 方法副本数,不模拟 HTTP 请求、Socket 连接或线程池排队行为 - 无请求生命周期:JMH 不发起网络调用、不解析 HTTP 头、不管理连接复用,无法体现 Netty/Servlet 容器层开销
-
结果单位不匹配:JMH 输出的是
ops/time(如 ops/ms)或ns/op,本质是单操作成本;QPS 是“单位时间完成请求数”,必须统计实际响应成功的请求数 - 屏蔽了关键瓶颈:JMH 主动规避 GC、STW、锁竞争、上下文切换——而这些恰是高 QPS 下最常出现的性能墙
想科学测算 QPS,该怎么做
用 JMeter 或类似工具,配合以下关键实践:
- 固定目标吞吐量 + 动态调优线程数:用 Constant Throughput Timer 控制期望 QPS,观察平均响应时间、错误率、95% 延迟是否达标;再逐步提升,找到稳定拐点
- 监控配套指标:同步采集 JVM GC 次数、Young/Old 区使用率、线程池活跃数、CPU load、系统内存页换入换出等,避免把“QPS 上不去”误判为代码问题
- 区分 warmup 和 measurement 阶段:先运行 2–3 分钟预热,让 JIT 编译完成、连接池填满、缓存预热;再开启正式采样,至少持续 5 分钟以上取聚合报告中的吞吐量均值
-
避免计时位置错误:不在主线程调用
invokeAll()前后计时,而应让每个请求任务自己记录 start/end 时间,并由压测工具汇总统计
那 nanoTime 在 QPS 场景里起什么作用
它只用于单请求内部耗时拆解,例如:
- 在 Spring AOP 或过滤器中,用
NanoTimer记录 Controller 入口到返回之间的总耗时 - 对 DB 查询、Redis 调用、JSON 序列化等子环节分别打点,定位慢在哪一环
- 注意:每次 nanoTime() 调用有 10–50ns 开销,高频打点本身会污染结果;应优先用异步日志或采样方式(如每 100 次记录一次)











