Java性能测试与基准测试
性能测试验证优化效果,基准测试量化方法性能。
性能测试类型
| 类型 | 目的 | 工具 |
|---|---|---|
| 基准测试 | 单方法性能 | JMH |
| 压力测试 | 系统容量 | JMeter |
| 负载测试 | 正常负载表现 | JMeter |
| 稳定性测试 | 长时间运行 | 自建脚本 |
JMH基准测试
什么是JMH
JMH(Java Microbenchmark Harness)是OpenJDK提供的基准测试框架,避免手动测试的常见陷阱。
JMH使用示例
Java
@BenchmarkMode(Mode.AverageTime) // 平均执行时间
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1) // 预热5轮
@Measurement(iterations = 10, time = 1) // 测试10轮
@Fork(1) // 启动1个进程
@State(Scope.Thread) // 状态线程隔离
public class StringBenchmark {
@Benchmark
public String stringConcat() {
String s = "";
for (int i = 0; i < 10; i++) {
s += i;
}
return s;
}
@Benchmark
public String stringBuilder() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append(i);
}
return sb.toString();
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(StringBenchmark.class.getSimpleName())
.build();
new Runner(opt).run();
}
}
JMH输出结果
Java
Benchmark Mode Cnt Score Error Units
StringBenchmark.stringConcat avgt 10 450.123 ± 12.34 ns/op
StringBenchmark.stringBuilder avgt 10 85.456 ± 5.67 ns/op
解读:
- Score:平均执行时间
- Error:误差范围
- stringBuilder比stringConcat快5倍
JMH注解说明
| 注解 | 作用 |
|---|---|
| @BenchmarkMode | 测试模式:AverageTime、Throughput |
| @OutputTimeUnit | 时间单位 |
| @Warmup | 预热配置:让JIT编译生效 |
| @Measurement | 测试配置 |
| @Fork | 进程数:避免进程间影响 |
| @State | 状态共享级别 |
| @Setup | 初始化方法 |
| @TearDown | 清理方法 |
JMH陷阱避免
Bash
// 陷阱1:死代码消除
@Benchmark
public int wrong() {
int x = 1 + 2; // 可能被JIT优化掉
return x; // 必须返回
}
// 陷阱2:常量折叠
@Benchmark
public int wrong() {
return 1 + 2; // JIT直接返回3
}
// 推荐:使用Blackhole消费结果
@Benchmark
public void correct(Blackhole bh) {
int x = compute();
bh.consume(x); // 防止优化
}
JMeter压力测试
JMeter基本配置
Java
┌─────────────────────────────────────┐
│ JMeter测试计划 │
├─────────────────────────────────────┤
│ Thread Group(线程组) │
│ - 线程数:100 │
│ - Ramp-Up:10秒 │
│ - 循环次数:10 │
│ │
│ Sampler(采样器) │
│ - HTTP Request │
│ │
│ Listener(监听器) │
│ - Summary Report │
│ - Aggregate Report │
│ │
└─────────────────────────────────────┘
JMeter参数说明
| 参数 | 说明 |
|---|---|
| 线程数 | 并发用户数 |
| Ramp-Up | 启动全部线程的时间 |
| 循环次数 | 每个线程执行次数 |
| 吞吐量 | 每秒请求数(TPS) |
| 响应时间 | 平均/最大响应时间 |
| 错误率 | 失败请求百分比 |
JMeter结果分析
text
Summary Report:
+--------+--------+--------+--------+--------+
| Label | Samples| Average| Error% | TPS |
+--------+--------+--------+--------+--------+
| HTTP | 10000 | 50ms | 0.1% | 200 |
+--------+--------+--------+--------+--------+
关键指标:
- Samples:总请求数
- Average:平均响应时间
- Error%:错误率(应<1%)
- TPS:吞吐量(每秒请求数)
性能指标分析
核心指标
| 指标 | 说明 | 标准 |
|---|---|---|
| TPS/QPS | 每秒请求数 | 根据业务需求 |
| 响应时间 | 平均响应时间 | <100ms优秀 |
| P99响应时间 | 99%请求响应时间 | <500ms |
| 错误率 | 失败请求比例 | <1% |
| CPU使用率 | CPU占用 | <70% |
| 内存使用率 | 内存占用 | <80% |
响应时间分布
text
┌─────────────────────────────────────┐
│ 响应时间分布 │
├─────────────────────────────────────┤
│ │
│ P50 = 50ms (50%请求小于50ms) │
│ P90 = 80ms (90%请求小于80ms) │
│ P99 = 200ms (99%请求小于200ms) │
│ P999 = 500ms (99.9%请求小于500ms) │
│ │
│ P99/P999更能反映用户体验 │
│ │
└─────────────────────────────────────┘
压测流程
text
┌─────────────┐
│ 确定目标 │ ← TPS、响应时间、并发数
└─────────────┘
↓
┌─────────────┐
│ 设计场景 │ ← 正常、峰值、极限场景
└─────────────┘
↓
┌─────────────┐
│ 配置工具 │ ← JMeter线程组、采样器
└─────────────┘
↓
┌─────────────┐
│ 执行测试 │ ← 分阶段执行
└─────────────┘
↓
┌─────────────┐
│ 收集结果 │ ← 日志、监控数据
└─────────────┘
↓
┌─────────────┐
│ 分析优化 │ ← 定位瓶颈,调优
└─────────────┘
监控配合
压测时配合监控:
text
# CPU监控
top -H -p <pid>
# 内存监控
jstat -gc <pid> 1000
# 网络监控
netstat -an | grep <port>
# 系统监控
vmstat 1
iostat -x 1
压测注意事项
- 预热阶段:让JIT编译生效,避免冷启动影响
- 渐进加压:从低并发逐步增加,避免直接高压
- 持续时间:至少10-15分钟,观察稳定性
- 隔离环境:独占测试环境,避免干扰
- 数据准备:足够测试数据,避免数据量影响
基准测试最佳实践
text
// 1. 预热让JIT生效
@Warmup(iterations = 5)
// 2. 多轮测试取平均值
@Measurement(iterations = 10)
// 3. 多进程避免相互影响
@Fork(3)
// 4. 防止死代码消除
public void test(Blackhole bh) {
bh.consume(result);
}
// 5. 合理设置状态共享
@State(Scope.Thread) // 线程隔离
@State(Scope.Benchmark) // 全局共享
注意事项
JMH预热很重要,JIT编译影响结果
压测要渐进加压,避免直接高压崩溃
关注P99而非平均值,反映真实用户体验
压测需在独立环境,避免其他因素干扰
结果需多次验证,单次结果不可靠
要点总结
- JMH是基准测试标准工具,避免手动测试陷阱
- 基准测试需预热、多轮、多进程
- JMeter适合压力测试,关注TPS和响应时间
- P99响应时间比平均值更能反映用户体验
- 压测需配合监控,全面分析性能表现
📝 发现内容有误?点击此处直接编辑