🚀 从压测到优化:用 k6 和 SpringBoot 构建高性能系统(附实战案例)

🚀 从压测到优化:用 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 / 响应时间 / 错误率] 
      ↓
[发现瓶颈 → 优化] 
      ↓
[重新压测验证]

✉️ 后记:从"跑压测"到"做性能工程师"

你做压测的目的,不是为了跑个数字,而是:

找到瓶颈 → 分析原因 → 有的放矢地优化 → 再次验证效果

哪怕你只是一个业务开发,只要你写接口,你就得关心这两个问题:

  • 你写的接口,抗得住压力吗?
  • 抗不住的时候,应该优化哪儿?

当你能回答这些问题时,你就已经开始走上"性能工程师"的进阶之路了。


📌 如果你觉得这篇文章对你有帮助,欢迎点赞 / 收藏 / 转发!如果你有实际案例或遇到压测难题,也欢迎留言交流,一起学习进步。

相关推荐
叫我阿柒啊3 小时前
Java全栈开发面试实战:从基础到微服务架构
java·vue.js·spring boot·redis·git·full stack·interview
你的人类朋友3 小时前
【操作系统】Unix和Linux是什么关系?
后端·操作系统·unix
uzong4 小时前
半小时打造七夕传统文化网站:Qoder AI编程实战记录
后端·ai编程
快乐就是哈哈哈4 小时前
从传统遍历到函数式编程:彻底掌握 Java Stream 流
后端
ningqw5 小时前
JWT 的使用
java·后端·springboot
追逐时光者5 小时前
精选 2 款 .NET 开源、实用的缓存框架,帮助开发者更轻松地处理系统缓存!
后端·.net
David爱编程6 小时前
指令重排与内存屏障:并发语义的隐形守护者
java·后端
胡gh6 小时前
数组开会:splice说它要动刀,map说它只想看看。
javascript·后端·面试
Pure_Eyes6 小时前
go 常见面试题
开发语言·后端·golang
ZZHow10247 小时前
Java项目-苍穹外卖_Day1
java·spring boot·web