Skip to content
返回质量保障

负载测试

施加真实和峰值流量,找到吞吐上限和第一个崩点。

为什么

性能问题在低流量下不出现。一个查询一个用户 50ms,1000 并发用户打同一未索引列就 50 秒,数据库连接池在 200 并发请求时耗尽而非 10。负载测试是在用户之前发现这些上限的唯一方式——在发布、营销推送、病毒时刻。目标不是为幻灯片产一个大数字;而是找到第一个瓶颈,理解为何崩,决定修它还是用自动扩缩和限流绕过它。

何时使用

任何发布前,任何可能引爆流量的营销事件前,以及作为周期性基线(每月)抓性能漂移。任何重大架构变更后(新缓存层、数据库迁移)也要跑。

如何做

1. 从真实分析定义负载画像,非猜测
   - 从 APM 拉最近 30 天的 p50、p95、p99 请求率
   - 确定峰值小时和端点混合(60% GET /products、20% POST /orders…)
   - 设目标:"持续 2x 峰值 10 分钟,p95 < 500ms"

2. 选能产生该量的工具
   - k6(JS、开发者友好、支持 10k+ VU)或 Locust(Python)
   - Gatling(Scala、报告丰富)用于企业场景
   - 从真能产生负载的机器跑(非你的笔记本)

3. 渐进爬升,别猛砸
   - 0 → 100 VU 用 2 分钟,保持 100 五分钟,爬到 500 用 2 分钟,保持
   - 突然尖峰啥也看不出——你分不清上限和冷启动

4. 负载下监控系统,非仅看测试结果
   - 看 CPU、内存、DB 连接、缓存命中率、错误率、p99 延迟
   - 第一个飙升的指标就是瓶颈;记下当时的 VU 数

5. 找到上限后停下分析
   - 加负载直到错误率 > 1% 或 p95 > 目标——那就是上限
   - profile 瓶颈(慢查询、连接池、GC 暂停、锁竞争)
   - 修或扩容,再测确认上限移动

示例

// k6 脚本: load-test-checkout.js
import http from "k6/http";
import { check, sleep } from "k6";
import { Rate, Trend } from "k6/metrics";

const errorRate = new Rate("checkout_errors");
const latency = new Trend("checkout_latency");

export const options = {
  stages: [
    { duration: "2m", target: 100 },   // 爬到 100 VU
    { duration: "5m", target: 100 },   // 保持 100
    { duration: "2m", target: 500 },   // 爬到 500
    { duration: "5m", target: 500 },   // 保持 500——找上限
    { duration: "2m", target: 0 },     // 降下
  ],
  thresholds: {
    http_req_duration: ["p(95)<500"],  // 95% 请求低于 500ms
    checkout_errors: ["rate<0.01"],    // < 1% 错误
  },
};

export default function () {
  const res = http.post("https://staging.example.com/api/checkout", JSON.stringify({
    product_id: 42, qty: 1, token: __ENV.TEST_TOKEN,
  }), { headers: { "Content-Type": "application/json" } });

  errorRate.add(res.status !== 200);
  latency.add(res.timings.duration);
  check(res, { "状态 200": (r) => r.status === 200 });
  sleep(1); // 1 秒思考时间
}

// 运行: k6 run --env TEST_TOKEN=xxx load-test-checkout.js

常见问题

  • ⚠从单台笔记本跑负载测试无法产生目标量——测试报"达到 5000 RPS"但笔记本网络是瓶颈,真实系统能扛 50k。
  • ⚠用均匀随机数据而非真实分布意味着每个请求打不同商品,缓存永远不热,你测的是冷读性能而非真实混合负载。
  • ⚠瞬间砸 1000 VU 而非爬升——你看到崩但分不清是冷启动(连接池初始化)、稳态负载还是真上限。
  • ⚠只测快乐路径不测错误路径(支付拒绝、缺货)意味着错误处理路径在负载下未测,而它们自己可能就是瓶颈。

最佳实践

  • ✓从有足够 CPU 和网络带宽的机器跑负载生成器——与目标同区域的云 VM,或 10k+ VU 用分布式 k6 集群。
  • ✓从真实 APM 数据(请求混合、峰值小时、思考时间)推导负载画像,使测试复现真实生产负载而非合成均匀打。
  • ✓测试中监控目标系统内部(DB 连接、缓存命中率、GC 时间)——测试结果告诉你它崩了,监控告诉你为何。
  • ✓把第一次负载测试当基线测量而非通过/失败——记下上限和瓶颈,每次优化后再测确认改善。