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

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

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

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

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

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

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


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

相关推荐
小醉你真好12 分钟前
Spring Boot + ShardingSphere 实现分库分表 + 读写分离实战
spring boot·后端·mysql
我爱娃哈哈41 分钟前
微服务拆分粒度,拆得太细还是太粗?一线架构师实战指南!
后端·微服务
泉城老铁1 小时前
EasyPoi实现百万级数据导出的性能优化方案
java·后端·excel
斜月1 小时前
Spring 自动装配原理即IOC创建流程
spring boot·后端·spring
有追求的开发者1 小时前
基于Django和APScheduler的轻量级异步任务调度系统
后端
泉城老铁1 小时前
Spring Boot 整合 EasyPoi 实现复杂多级表头 Excel 导出的完整方案
java·后端·excel
CF14年老兵1 小时前
🔥 2025 年开发者必试的 10 款 AI 工具 🚀
前端·后端·trae
京东云开发者1 小时前
本地缓存 Caffeine 中的时间轮(TimeWheel)是什么?
后端
半部论语2 小时前
Spring **${}** vs **#{}** 语法全景图
java·数据库·spring boot·后端·spring
京东云开发者2 小时前
缓存之美:万文详解 Caffeine 实现原理(上)
后端