基线、压测与性能回归:怎样证明优化有效且安全
可比性来自受控实验,不来自两张漂亮报表。
OpenJDK JMH 是构建、运行和分析 JVM 微/毫/宏基准的工具框架。
故障现场:局部数字为什么会给出错误结论
候选版本吞吐高 8%,但测试机器、JDK、数据热度和负载模型都不同;p99 从 180 ms 退化到 205 ms,报告仍因平均吞吐上升宣布成功。 第一条规则是同时保存负载输入、业务输出和资源水位;只有结果数字而没有发生条件,无法区分代码变化、环境噪声、缓存热度和依赖波动。
先固定权威测量对象
微基准验证热点代码,组件基准验证真实依赖,服务压测验证排队与保护;每层都先证明输出正确,禁止用少做工作换取性能。 正向实验达到预期吞吐和延迟,反向实验制造饱和、队列、暂停或依赖退化,并证明指标能揭示而非掩盖差异。
六段性能主链
Hypothesis
在 Hypothesis 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
Environment lock
在 Environment lock 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
Warmup
在 Warmup 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
Steady samples
在 Steady samples 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
Compare
在 Compare 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
Regression gate
在 Regression gate 阶段记录时间戳、计数、资源 owner、上限和失败原因。测量探针的开销单独评估;并行阶段按关键路径组合,串行阶段才允许求和。改变参数后重新验证上下游水位,避免把等待从一个队列搬到另一个队列。
性能结论先声明系统边界与负载模型
分布、排队和守恒关系必须同时成立
平均值会把少量严重长尾稀释,最大值又容易受单个噪声支配。保存原始直方图或足够精细的 bucket,报告 p50/p95/p99/max、样本数和窗口。跨实例聚合应合并 bucket 后再算分位数,不能平均各实例 p99。桶上界低于真实尾部会把所有慢请求塞进 +Inf,精度看似稳定其实失去判别力。
负载发生器也会制造测量错误
资源池必须沿同一截止时间协作
虚拟线程降低线程持有成本,不增加数据库连接、CPU 或远端 QPS;连接池扩大会增加数据库活跃会话和锁竞争;批量与压缩减少网络调用却增加内存、延迟和 codec CPU。任何参数变化都观察瓶颈是否迁移,不能只看被优化局部的耗时。
JVM、GC 与操作系统证据不能脱离业务负载
CPU 利用率低不代表有余量,线程可能等锁、连接、磁盘或网络;CPU 高也可能是序列化、压缩、GC、TLS 或自旋而非业务计算。结合运行队列、上下文切换、缺页、磁盘时延、网络重传和容器 throttling,先定位资源需求再调整参数。
性能数据同样需要安全与治理
用阶梯负载画出拐点而不是只压一个峰值
分层剖析必须回答时间和资源去了哪里
基准结果需要反事实与可回滚证据
两个 Java 17 模型固定量化见证
离线模型不冒充真实压测,只固定公式、边界和判定输出;真实环境再用直方图、JFR/GC 日志、数据库与消息指标证明同一不变量。
javac --release 17 -Xlint:all -Werror examples/backend-development/performance/baseline-load-regression/BenchmarkStatisticsDemo.java examples/backend-development/performance/baseline-load-regression/RegressionGateDemo.java
java -cp examples/backend-development/performance/baseline-load-regression BenchmarkStatisticsDemo
java -cp examples/backend-development/performance/baseline-load-regression RegressionGateDemobaselineMedian=100 candidateMedian=88 improvementPct=12.0 runs=5 stable=true
p99BaselineMs=180 p99CandidateMs=205 throughputChangePct=8 errorRate=0.0 regression=true reasons=[P99]容量、回归与恢复门禁
保存 commit、JDK、参数、CPU/内存/容器限额、数据规模、预热、持续时间、到达模型、并发、重复数和原始直方图,使用相同统计规则比较。 围绕“性能对比固定代码、环境、负载和统计方法,以重复样本及功能正确性共同决定回归”保存基线、候选、差值、原始分布和权威结果。过载实验还要证明拒绝有界、关键流量受保护、积压排空且恢复迟滞不会制造二次冲击;不满足任一项即阻止发布或自动回滚。
