🚀 从压测到优化:用 k6 和 SpringBoot 构建高性能系统(附实战案例)
📌 前言:为什么你必须懂压测?
只要你在写后端接口,早晚都会被问到这些问题:
- 你的接口能扛多少并发?
- 系统性能瓶颈在哪?
- 如何判断系统是否"抗压"?
这篇博客不会卖弄复杂术语,而是带你从 零基础压测 出发,一步步讲清楚:
- 如何使用 k6 进行接口压测
- 如何根据压测结果定位性能瓶颈
- SpringBoot 项目中,哪些地方最容易出问题
- 如何调优让系统"越跑越快"
🧪 一、压测的目的是什么?SLA 是什么?
做压测并不是为了跑数字图好看,而是为了回答几个核心问题:
- 系统的处理能力极限是多少?
- 系统能否在高并发下保持稳定?
- 是否满足业务的 服务等级协议(SLA)?
🔍 什么是 SLA?
SLA(Service Level Agreement)即服务等级协议,定义了我们对系统性能的"承诺":
指标 | 示例要求 |
---|---|
响应时间 | p95 < 500ms |
错误率 | < 1% |
吞吐量 | ≥ 1000 QPS |
可用性 | ≥ 99.9% |
压测的目的就是验证系统是否能满足这些 SLA。
⚙️ 二、使用 k6 对 SpringBoot 接口进行压测
1. 安装 k6
bash
brew install k6 # macOS
choco install k6 # Windows
或使用 Docker:
bash
docker run -i grafana/k6 run - <test.js
2. 编写压测脚本(test.js)
javascript
import http from 'k6/http';
import { check } from 'k6';
export const options = {
vus: 100,
duration: '30s',
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
}
};
export default function () {
const res = http.post('http://localhost:8080/api/pay', JSON.stringify({
amount: 100,
currency: 'USD',
}), {
headers: { 'Content-Type': 'application/json' },
});
check(res, {
'status is 200': (r) => r.status === 200,
});
}
3. 执行压测
bash
k6 run test.js
你会得到如下指标:
- 请求总数 / 每秒请求数(RPS)
- 响应时间分布(p50/p95/p99)
- 失败请求数 / 错误率
📊 三、如何分析压测结果?
重点看这几个指标:
指标 | 说明 |
---|---|
RPS(requests per second) | 吞吐量:系统每秒能处理的请求数 |
响应时间(http_req_duration) | 响应时间分布 |
失败率(http_req_failed) | 请求错误的比率 |
CPU 使用率 | 是否达到瓶颈 |
系统负载 | 是否过载,是否抖动 |
🔍 四、根据压测结果定位性能瓶颈(实战案例)
✅ 案例 1:响应时间高,p95 超 2 秒
压测结果:
ini
http_req_duration: avg=1200ms, p95=2200ms ❌
http_req_failed: 0.1%
排查方法:
- 查看慢 SQL 日志 → 某个 SQL 没加索引
- 用 explain 分析 → 加上索引后,p95 降为 400ms
优化措施:
- SQL 加索引
- 缓存热点查询(如 Redis)
✅ 案例 2:RPS 上不去,CPU 利用率只有 40%
表现:
- 请求处理慢
- CPU 没吃满
分析思路:
- 排查线程 dump → 大量线程等待数据库连接
- 查看连接池配置:HikariCP maxPoolSize 可能太低
优化措施:
- 将连接池扩大
- 分析数据库瓶颈,进行 SQL 优化
✅ 案例 3:高并发下系统抖动,p99 = 3s
表现:
- p95 正常,p99 极高
- 请求偶尔阻塞
原因:
- 某些请求依赖外部接口(如支付/物流),偶尔超时
- 线程池被拖死,导致其他请求排队
优化方案:
- 外部请求加超时控制(例如 500ms)
- 使用隔离线程池 / 服务降级
- 非核心流程走异步队列(MQ)
🧠 五、CPU 利用率和吞吐量的关系
❓很多人问:"我的 CPU 才用了 30%,是不是说明还有性能空间?"
✅ 正确理解:
- CPU 使用率过低 (<50%):系统大概率是 IO 阻塞
- CPU 使用率在 80-90% 且稳定:资源利用充分,是性能调优的理想状态
- CPU >95% 且响应时间上升:可能出现性能瓶颈或雪崩
推荐做法:
- 用压测手段将 CPU 利用率"推高",同时观察响应时间、错误率
- 在性能目标和系统稳定性之间找"最佳点"
🧰 六、SpringBoot 项目中的常见优化点
组件 | 优化方向 |
---|---|
数据库连接池 | 合理配置 HikariCP maximumPoolSize |
SQL 查询 | 加索引 / 分页 / limit 查询优化 |
缓存 | Redis 缓存热点数据,避免穿透和击穿 |
线程池 | 自定义线程池,避免全局线程被堵塞 |
网络调用 | 设置连接超时 / 读写超时 |
GC 配置 | 调整 JVM GC 策略(如 G1、ZGC) |
限流降级 | 使用 Sentinel、RateLimiter 等 |
异步任务 | 使用 MQ、@Async、CompletableFuture 等 |
✅ 七、压测流程总结图
css
[编写 k6 脚本]
↓
[设定目标 SLA]
↓
[执行压测并记录指标]
↓
[查看系统监控:CPU / 响应时间 / 错误率]
↓
[发现瓶颈 → 优化]
↓
[重新压测验证]
✉️ 后记:从"跑压测"到"做性能工程师"
你做压测的目的,不是为了跑个数字,而是:
找到瓶颈 → 分析原因 → 有的放矢地优化 → 再次验证效果
哪怕你只是一个业务开发,只要你写接口,你就得关心这两个问题:
- 你写的接口,抗得住压力吗?
- 抗不住的时候,应该优化哪儿?
当你能回答这些问题时,你就已经开始走上"性能工程师"的进阶之路了。
📌 如果你觉得这篇文章对你有帮助,欢迎点赞 / 收藏 / 转发!如果你有实际案例或遇到压测难题,也欢迎留言交流,一起学习进步。