系统容量规划与压测实战:从1万到100万QPS的科学扩容

系统容量规划与压测实战:从1万到100万QPS的科学扩容

大家好,我是迪哥。2026 年 618 前,我们的预估峰值从 10 万 QPS 涨到了 100 万 QPS,压测发现瓶颈在数据库连接池,扩容了 20 倍才顶住。今天聊聊,如何科学地做容量规划和压测,不让你的系统死在峰值。

为什么要做容量规划?

2023 年我们踩过坑:

  • ❌ 618 峰值预估 5 万,实际来了 20 万,系统直接雪崩
  • ❌ 为了保险,提前扩容了 10 倍,成本超了 3 倍
  • ❌ 不知道瓶颈在哪,瞎扩容,钱花了性能没上去

容量规划三步法

1. 建立性能基准线

单机性能测试:

bash 复制代码
# 用 JMeter 或者 wrk 压测
wrk -t12 -c400 -d30s http://localhost:8080/api/order

# 结果示例
Running 30s test @ http://localhost:8080/api/order
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    20.5ms   15.2ms  200.5ms   89.00%
    Req/Sec    5000.0   200.0    6000.0    90.00%
  1800000 requests in 30.00s, 2.50GB read
Requests/sec:  60000.00  ← 单机 6 万 QPS

基准表:

指标 数值
单机 QPS 60000
单机 CPU 峰值 80%
单机内存峰值 8GB
数据库最大连接数 2000

2. 预估峰值 & 冗余系数

复制代码
预估峰值 QPS = 历史峰值 × 增长系数 × 突发系数
           = 5万 × 2倍 × 1.5倍
           = 15万 QPS

需要机器数 = 预估峰值 / 单机 QPS × 冗余系数
          = 15万 / 6万 × 1.3
          ≈ 4台

但实际是 100 万,所以需要 100万 / 6万 × 1.3 ≈ 22台

经验值:

  • 日常冗余系数:1.3-1.5
  • 大促冗余系数:2-3
  • 新业务:3-5倍冗余

3. 识别瓶颈 & 扩容

压测实战:JMeter

安装 JMeter

下载:https://jmeter.apache.org/download_jmeter.cgi

测试计划

复制代码
Test Plan
└── Thread Group (1000 threads, 10s ramp-up, 300s duration)
    ├── HTTP Request (POST /api/order)
    ├── View Results Tree
    └── Summary Report

关键监控指标

层级 指标 告警阈值
系统 CPU > 80%
系统 Load Average > CPU 核数
系统 内存 > 85%
系统 网络带宽 > 80%
JVM Heap Used > 80%
JVM GC 次数 Full GC > 3次/5分钟
应用 错误率 > 0.1%
应用 P99 延迟 > 500ms
中间件 数据库连接池 > 90%
中间件 Redis 连接池 > 90%

瓶颈定位示例

现象:

  • 应用 QPS 上不去,CPU 只有 30%
  • 错误率上升,提示 GetConnectionTimeoutException

定位:

yaml 复制代码
# application.yml
spring:
  datasource:
    hikari:
      maximum-pool-size: 20  ← 太小了!

优化:

yaml 复制代码
spring:
  datasource:
    hikari:
      maximum-pool-size: 200  # 改成 200

全链路压测

单系统压测不够,要全链路!

复制代码
 压测工具 → 网关 → 订单服务 → 库存服务 → 数据库
                                          ↓
                                        Redis

关键点:

  1. ✅ 影子表(数据库隔离)
  2. ✅ 消息隔离(避免污染真实数据)
  3. ✅ 灰度流量(从 10% 开始逐步放大)

压测脚本:Go 版本

go 复制代码
package main

import (
    "fmt"
    "net/http"
    "sync"
    "time"
)

func main() {
    concurrency := 1000
    requests := 1000000
    var wg sync.WaitGroup
    client := &http.Client{Timeout: 10 * time.Second}

    start := time.Now()
    for i := 0; i < concurrency; i++ {
        wg.Add(1)
        go func(workerID int) {
            defer wg.Done()
            for j := 0; j < requests/concurrency; j++ {
                resp, err := client.Get("http://localhost:8080/api/order")
                if err != nil {
                    continue
                }
                resp.Body.Close()
            }
        }(i)
    }
    wg.Wait()
    duration := time.Since(start)
    qps := float64(requests) / duration.Seconds()
    fmt.Printf("QPS: %.0f, Duration: %v\n", qps, duration)
}

容量规划表格

系统 单机 QPS 预估峰值 冗余系数 所需机器 现状机器 是否要扩容
订单服务 60000 100万 1.5 25 10 ✅ 是
库存服务 80000 80万 1.5 15 8 ✅ 是
用户服务 40000 30万 1.5 11 12 ❌ 否
网关 15万 100万 1.5 10 5 ✅ 是

经验总结

  1. 不要瞎拍脑袋! 基于历史数据 + 增长预期
  2. 先压测再扩容! 不然钱花了,性能没上去
  3. 容量规划是动态的! 每季度重估一次
  4. 监控是前提! 没有监控,谈何容量规划
  5. 灰度很重要! 别一上来全量,从 10% 开始

说到容量规划,我家那只叫 Docker 的哈士奇最近饭量从 1 碗涨到了 4 碗,我要是早做容量规划,就不至于三天买一次狗粮了 😂

我是迪哥,我们下期再见!


往期推荐:

相关推荐
weixin_408099679 分钟前
2026 图片去水印 API 接口完全指南:一键去除图片水印(附 Python/Java/PHP/C# 示例)
java·python·php·图片处理·api调用·图片去水印·石榴智能
钱六两34 分钟前
#3、SpringAI 接入deepSeek大模型(喂饭版)
java·spring boot·ai编程
null_172 小时前
IntelliJ IDEA 极致流畅配置方案:Ultra 9 285K + 64GB 内存实测
java·ide·intellij-idea
Herbert_hwt2 小时前
建立Java程序开发
java·开发语言
好好沉淀2 小时前
@ExcelIgnoreUnannotated 和 @AutoMapper 详解
java
愚公移码2 小时前
蓝凌EKP18产品:流程虚拟机(PVM)
java·开发语言·前端
驰骋工作流3 小时前
流程引擎BPM设计之:流程消息
java·工作流引擎·bpm·jflow·ccflow
dogstarhuang3 小时前
从 0 到 1 搭建可收费的 API 开放平台(实战)
java·架构·api
VortMall3 小时前
『平台去经营化』平台治理能力全新重构|VortMall微服务商城系统v1.3.10
java·大数据·微服务·商城系统·开源商城·vortmall·去经营化
吴声子夜歌4 小时前
Redis 3.x——集群故障转移
java·数据库·redis·集群