面向 HTTP 协议的性能压测与调优指南 | 优测全链路压力测试平台

适用场景:APP/小程序/Web应用在高峰期出现接口变慢、页面加载等待、超时、错误率升高、CPU/内存/数据库连接吃紧等问题。
测试对象:服务后台后端 HTTP/HTTPS API、网关、鉴权服务、业务服务、缓存、数据库、第三方依赖链路。
目标:建立可复现、可量化、可持续的 HTTP 性能测试体系,定位高峰期瓶颈,并形成可验证的调优闭环。

1. 性能测试先讲结论:不要直接“猛压”

高峰期性能不佳,不能只靠一次大并发压测判断问题。正确做法是:

  1. 先建基线:确认当前单接口、核心链路、正常流量下的响应时间、吞吐、错误率。
  2. 再建模型:根据真实高峰流量、用户行为、接口占比设计压测场景。
  3. 逐级加压:从基准负载到峰值负载,再到极限负载,观察拐点。
  4. 定位瓶颈:结合客户端指标、HTTP 指标、应用指标、中间件指标、数据库指标一起分析。
  5. 调优验证:每次只改一类关键变量,做前后对比,证明优化有效。

性能测试不是“看服务器能不能扛住”,而是回答四个问题:

  • 高峰期到底慢在哪里?
  • 当前系统稳定承载能力是多少?
  • 超过多少流量会开始劣化?
  • 做哪些优化能以最小成本换来最大收益?

2. 测试目标与 SLA 建议

2.1 核心 SLA 指标

指标 建议目标 说明
接口成功率 ≥ 99.9% 业务成功,不只是 HTTP 200
HTTP 错误率 < 0.1% 5xx、网关超时、连接失败等
P95 响应时间 核心接口 < 500ms 95% 请求应在目标内完成
P99 响应时间 核心接口 < 1000ms 用于观察尾延迟
登录/下单/支付等关键链路 P95 < 1.5s 多接口串联链路按用户感知计算
吞吐量 ≥ 高峰 QPS × 1.3 至少预留 30% 容量冗余
CPU 使用率 稳态 < 70% 峰值可短暂到 80%,不建议长期满载
内存使用率 稳态 < 75% 重点观察泄漏与 GC
数据库连接池 使用率 < 80% 避免连接耗尽导致雪崩

性能结论必须基于分位数,不能只看平均值。平均值很好看,P95/P99 可能已经在“排队挨打”。

2.2 高峰期容量目标

建议以真实业务流量倒推:

目标峰值 QPS = 峰值分钟请求量 / 60
压测目标 QPS = 目标峰值 QPS × 安全系数
安全系数建议:1.3 ~ 2.0

示例:

历史峰值分钟请求量:120,000 次
目标峰值 QPS:120,000 / 60 = 2,000 QPS
压测验收 QPS:2,000 × 1.5 = 3,000 QPS

3. HTTP 性能测试指标体系

3.1 客户端侧指标

指标 含义 关注点
DNS Lookup 域名解析耗时 DNS 缓存、解析服务质量
TCP Connect TCP 建连耗时 网络延迟、连接复用
TLS Handshake HTTPS 握手耗时 TLS 配置、证书链、会话复用
TTFB 首字节时间 服务端处理和链路延迟
Download Time 响应体下载耗时 响应体大小、带宽、压缩
Total Duration 总耗时 用户感知最直接指标

3.2 服务端侧指标

层级 指标
网关/Nginx/API Gateway QPS、活跃连接数、5xx、499/504、 upstream 响应时间
应用服务 CPU、内存、线程池、协程/事件循环、GC、错误日志、慢接口
JVM/Go/Node/Python Runtime GC pause、堆内存、goroutine、event loop lag、线程阻塞
缓存 命中率、延迟、连接数、热 key、大 key
数据库 QPS、慢查询、锁等待、连接数、缓存命中率、主从延迟
消息队列 积压量、消费延迟、生产/消费速率
第三方依赖 成功率、P95、限流、超时、重试次数

3.3 业务侧指标

HTTP 200 不等于业务成功。必须增加业务断言:

  • 登录是否返回 token
  • 下单是否生成订单号
  • 查询是否返回有效数据
  • 支付模拟是否返回明确状态
  • 列表分页是否符合预期
  • 错误码是否为业务可接受错误

4. 压测前准备清单

4.1 明确测试范围

至少确定以下内容:

  • APP/小程序版本、服务版本、测试环境或预发环境
  • 是否允许压生产;如压生产,必须限流、分时段、可回滚
  • 核心接口清单:登录、首页、列表、详情、搜索、提交、支付/下单、用户中心等
  • 依赖服务:缓存、数据库、对象存储、消息队列、第三方 API
  • 测试账号和测试数据规模
  • 是否需要绕过短信、验证码、支付真实扣款等外部动作

4.2 接口分级

建议按业务影响分为三级:

等级 接口类型 测试要求
P0 登录、首页、核心交易、支付、下单 必须做链路压测、峰值压测、故障观察
P1 列表、详情、搜索、用户信息 必须做接口压测和混合场景压测
P2 非核心配置、埋点、低频接口 做基准测试和限流验证

4.3 测试环境要求

理想状态是测试环境尽量接近生产:

  • 服务实例数、CPU、内存规格与生产一致或按比例缩放
  • 数据库数据量接近生产级别
  • 缓存预热策略与生产一致
  • CDN、网关、负载均衡配置接近生产
  • 日志级别不要开 debug,否则压测结果会被日志拖偏
  • 监控必须提前打通,否则压完只剩一个感受:“它好像不行”

5. HTTP 压测场景设计

5.1 单接口基准测试

目的:了解单个接口在低并发下的基础性能。

建议配置:

并发用户:1、5、10、20
持续时间:每组 3 ~ 5 分钟
关注指标:平均响应、P95、P99、错误率、响应体大小

适用结论:

  • 单接口自身是否慢
  • 是否存在固定耗时,如第三方调用、慢 SQL、冷启动
  • 响应体是否过大

5.2 负载测试

目的:验证系统在预期高峰流量下是否稳定。

建议模型:

预热:10% 峰值流量,5 分钟
正常高峰:100% 峰值流量,15 ~ 30 分钟
安全冗余:130% ~ 150% 峰值流量,15 分钟
降压:逐步降至 0,5 分钟

验收条件:

  • P95 满足 SLA
  • 错误率低于阈值
  • CPU/内存/数据库连接未逼近上限
  • 无明显错误日志堆积

5.3 压力测试

目的:找到系统性能拐点和最大承载能力。

执行方式:

从 30% 目标峰值开始,每 5 分钟提升 20% ~ 30%
持续提升,直到 P95 明显恶化、错误率升高或资源达到瓶颈
记录系统进入不稳定状态的流量点

重点观察:

  • QPS 到多少开始不再线性增长
  • P95/P99 从哪个点开始陡升
  • 先满的是 CPU、数据库、连接池、网关还是第三方依赖
  • 系统是否有雪崩、重试风暴、队列堆积

5.4 尖峰测试

目的:模拟活动开始、推送触达、秒杀入口打开等瞬时流量。

建议模型:

正常流量:30% 峰值,5 分钟
瞬时拉升:150% ~ 300% 峰值,1 ~ 3 分钟
恢复流量:50% 峰值,10 分钟

重点观察:

  • 自动扩容是否及时
  • 限流是否生效
  • 队列削峰是否有效
  • 高峰结束后系统是否恢复正常

5.5 稳定性测试

目的:验证长时间运行是否出现内存泄漏、连接泄漏、性能衰减。

建议模型:

流量:70% ~ 100% 目标峰值
持续时间:4 小时、8 小时或 24 小时

重点观察:

  • 内存是否持续上涨
  • GC 时间是否变长
  • 连接数是否只增不降
  • 日志、磁盘、队列是否堆积
  • P95 是否随时间逐步劣化

6. 压测流量模型设计

6.1 用户行为比例示例

高峰期通常不是所有接口平均访问。应按真实访问比例混合:

用户行为 接口示例 占比
启动/首页 /api/home, /api/config 25%
列表浏览 /api/items, /api/feed 30%
详情查看 /api/item/detail 20%
搜索 /api/search 10%
登录/刷新 token /api/auth/login, /api/auth/refresh 5%
提交/下单 /api/order/create 5%
用户中心 /api/user/profile 5%

6.2 Think Time

不要让压测脚本像机关枪一样无停顿地打接口。真实用户会浏览、等待、滑动、输入。

建议:

轻量浏览:1 ~ 3 秒
详情阅读:3 ~ 8 秒
搜索输入:2 ~ 5 秒
提交动作:1 ~ 2 秒

6.3 测试数据要求

  • 用户账号不少于并发用户数的 2 ~ 5 倍
  • 商品/内容/订单数据量尽量接近生产
  • 搜索关键词应覆盖热门词、长尾词、无结果词
  • 避免所有虚拟用户请求同一个数据,除非目的是测试热点 key
  • 写入类接口要有清理机制,避免测试数据污染后续测试

7. HTTP 压测脚本示例

以下示例适合做 HTTP API 混合场景压测,可根据您的实际场景和接口替换路径和断言。

import http from "k6/http";
import { check, sleep } from "k6";
import { Rate, Trend } from "k6/metrics";

const businessErrorRate = new Rate("business_error_rate");
const apiDuration = new Trend("api_duration");

export const options = {
  stages: [
    { duration: "5m", target: 100 },
    { duration: "15m", target: 500 },
    { duration: "15m", target: 800 },
    { duration: "5m", target: 0 }
  ],
  thresholds: {
    http_req_failed: ["rate<0.001"],
    http_req_duration: ["p(95)<500", "p(99)<1000"],
    business_error_rate: ["rate<0.001"],
    api_duration: ["p(95)<500"]
  }
};

const BASE_URL = __ENV.BASE_URL || "https://api.example.com";

function randomSleep(min, max) {
  const duration = Math.random() * (max - min) + min;
  sleep(duration);
}

function login() {
  const payload = JSON.stringify({
    username: `test_user_${__VU}`,
    password: "password123"
  });

  const res = http.post(`${BASE_URL}/api/auth/login`, payload, {
    headers: { "Content-Type": "application/json" },
    timeout: "3s"
  });

  const ok = check(res, {
    "login http 200": (r) => r.status === 200,
    "login has token": (r) => Boolean(r.json("token"))
  });

  businessErrorRate.add(!ok);
  apiDuration.add(res.timings.duration);
  return res.json("token");
}

function requestHome(token) {
  const res = http.get(`${BASE_URL}/api/home`, {
    headers: { Authorization: `Bearer ${token}` },
    timeout: "3s"
  });

  const ok = check(res, {
    "home http 200": (r) => r.status === 200,
    "home business success": (r) => r.json("code") === 0
  });

  businessErrorRate.add(!ok);
  apiDuration.add(res.timings.duration);
}

function requestList(token) {
  const page = Math.floor(Math.random() * 10) + 1;
  const res = http.get(`${BASE_URL}/api/items?page=${page}&size=20`, {
    headers: { Authorization: `Bearer ${token}` },
    timeout: "3s"
  });

  const ok = check(res, {
    "list http 200": (r) => r.status === 200,
    "list has data": (r) => Array.isArray(r.json("data"))
  });

  businessErrorRate.add(!ok);
  apiDuration.add(res.timings.duration);
}

function requestDetail(token) {
  const itemId = Math.floor(Math.random() * 10000) + 1;
  const res = http.get(`${BASE_URL}/api/item/detail?id=${itemId}`, {
    headers: { Authorization: `Bearer ${token}` },
    timeout: "3s"
  });

  const ok = check(res, {
    "detail http 200": (r) => r.status === 200,
    "detail business success": (r) => r.json("code") === 0
  });

  businessErrorRate.add(!ok);
  apiDuration.add(res.timings.duration);
}

export default function () {
  const token = login();
  if (!token) {
    sleep(1);
    return;
  }

  requestHome(token);
  randomSleep(1, 3);

  requestList(token);
  randomSleep(1, 3);

  requestDetail(token);
  randomSleep(2, 5);
}

执行命令示例

BASE_URL="https://api.example.com" k6 run app-http-load-test.js

建议输出 JSON 结果,便于后续分析:

BASE_URL="https://api.example.com" k6 run --summary-export result.json app-http-load-test.js

8. JMeter HTTP 压测设计建议

如果团队更熟悉 JMeter,可按以下结构搭建测试计划:

Test Plan
├── User Defined Variables
│   ├── BASE_URL
│   ├── APP_VERSION
│   └── DEVICE_TYPE
├── CSV Data Set Config
│   └── users.csv
├── Thread Group
│   ├── HTTP Header Manager
│   ├── HTTP Cookie Manager
│   ├── HTTP Request Defaults
│   ├── Login Request
│   ├── JSON Extractor: token
│   ├── Home Request
│   ├── List Request
│   ├── Detail Request
│   ├── Constant/Uniform Random Timer
│   └── Response Assertion
└── Backend Listener
    └── InfluxDB / Prometheus / Grafana

JMeter 注意事项:

  • 不要在高并发时开启 GUI 模式执行
  • 不要使用过多 View Results Tree,容易压垮压测机
  • 压测机 CPU 超过 70% 时,结果可能不可信
  • 使用分布式压测时,要保证各压测机网络、时钟、版本一致
  • 断言不能只校验状态码,要校验业务字段

9. 使用优测云压测工具落地 HTTP 性能测试

如果团队使用优测云压测工具,可以把前面的 HTTP 性能测试方法直接落到平台配置中。优测压力测试平台的价值不只是“发起压测”,更适合承担三件事:测试场景建模、链路编排、压测任务执行与结果沉淀

9.1 场景创建:优先选择“全链路 + HTTP”

优测压力测试平台支持新建测试场景时选择:

  • 单接口:适合做接口基线测试,比如单独验证登录、首页、列表、详情接口的 P95/P99。
  • 全链路:适合模拟真实用户路径,比如“登录 → 首页 → 列表 → 详情 → 提交”。高峰期性能问题通常发生在链路串联后,建议优先使用全链路。
  • 测试场景导入:适合把已有接口资产或历史场景迁移到压测平台。
  • 模板:适合复用标准压测模型,减少重复配置。

在协议选择上,本文聚焦 HTTP/HTTPS API,因此创建场景时建议选择 HTTP。如果后端链路中还包含 Dubbo、RPC、TCP、WebSocket、MQTT、SSE、QUIC 等协议,可以作为全链路中的扩展节点,但性能结论要分别统计,不要把不同协议的耗时混在一个口径里。

9.2 工具能力与测试设计的对应关系

优测压力测试平台能力 在 HTTP 性能测试中的用法
HTTP 请求节点 配置 GET/POST/PUT/DELETE 等接口请求
全链路场景 串联登录、首页、列表、详情、提交等用户路径
请求头/请求体/请求参数 设置 token、Content-Type、业务参数、分页参数
出参定义 提取 token、订单号、详情 ID,传给后续接口
请求结果断言 校验 HTTP 状态码、业务 code、返回字段,区分业务成功率
前置/后置处理器 做签名、加密、动态参数、响应清理、数据准备
高级配置 设置超时、重定向、连接策略、特殊请求配置
JDBC/Redis/RocketMQ 在链路中准备数据、验证缓存、模拟消息写入或消费
条件/循环/事务/并行/等待/集合点 还原真实用户行为、事务统计、尖峰并发和 Think Time
压力任务 设置并发/RPS、压测区域、执行时长、链路权重

9.3 HTTP API 节点配置建议

在“创建测试场景详情”页面中,HTTP API 节点至少应配置以下内容:

  1. API 描述:命名要能看懂业务含义,不建议只叫 API1、API2。推荐命名为“登录接口”“首页聚合接口”“商品列表接口”“订单提交接口”。
  2. 请求 URL:使用测试环境或预发环境域名,生产压测必须经过审批和限流保护。
  3. 请求方法:根据接口实际行为选择 GET、POST、PUT、DELETE 等。
  4. 协议类型:HTTP/HTTPS。HTTPS 场景要额外关注 TLS 握手和连接复用。
  5. 请求头:配置 Content-TypeAuthorization、设备标识、APP 版本、渠道、灰度标识等。
  6. 请求体/请求参数:参数要动态化,避免所有虚拟用户请求同一个资源导致结果失真。
  7. 出参定义:登录接口提取 token,列表接口提取 itemId,创建订单接口提取 orderId,供后续接口引用。
  8. 请求结果断言:必须同时校验 HTTP 状态码和业务字段。例如 HTTP 200 且 code=0 才算成功。
  9. 前置处理器:适合处理签名、时间戳、随机数、加密参数、测试数据初始化。
  10. 后置处理器:适合清理临时数据、记录关键字段、转换响应结果。
  11. 高级配置:统一设置超时时间、重定向、连接策略,避免默认配置与生产真实行为不一致。

示例配置口径:

API 名称:登录接口
请求方法:POST
协议类型:HTTPS
请求 URL:https://api.example.com/api/auth/login
请求头:Content-Type: application/json
请求体:{"username":"${username}","password":"${password}"}
断言:HTTP 状态码 = 200;响应 JSON 中 code = 0;token 不为空
出参:token = $.data.token

9.4 全链路编排建议

针对业务高峰期问题,建议在优测压力测试平台中不要只压单接口,而是建立全链路场景。推荐链路如下:

登录接口
→ 首页聚合接口
→ 列表接口
→ 详情接口
→ 搜索接口,可选
→ 提交/下单接口,可选
→ 用户中心接口

链路设计原则:

  • 登录不要占比过高:真实高峰通常不是所有用户都重新登录,登录/刷新 token 建议控制在 5% ~ 10%。
  • 列表和详情要动态参数化:避免全部请求集中到同一个 ID,除非目标是专门测试热点数据。
  • 写入类接口要做幂等:下单、提交、领取等接口必须使用测试数据和幂等键,避免脏数据或重复写入。
  • 用等待节点模拟 Think Time:浏览列表、阅读详情之间加入 1 ~ 5 秒等待,更接近真实用户。
  • 用事务控制器统计关键链路:将“登录 → 首页 → 列表 → 详情”包成一个事务,单独统计链路级 P95/P99。
  • 用集合点模拟瞬时高峰:活动开始、推送触达、秒杀入口打开等场景,可使用集合点制造同一时刻并发请求。
  • 用并行控制器模拟首屏并发请求:首屏经常同时请求配置、首页、推荐、用户信息,可用并行节点还原。

9.5 压力任务配置建议

在“创建压力测试任务”页面中,截图体现了几个关键配置项:压测模式、并发数、压测区域、执行机数量、执行时长、链路权重和压力引擎。

压测模式选择

模式 适用场景 建议
用户并发模式 模拟同时在线用户数 适合常规高峰、登录态链路、用户路径压测
RPS 模式 固定请求吞吐 适合网关/API 容量验证、单接口吞吐上限测试

如果目标是复现高峰期用户体验,优先选择用户并发模式;如果目标是验证某个 HTTP 接口或网关最大吞吐,选择 RPS 模式更直接。

并发数与时长

截图示例中并发数为 100、压测时长为 5 分钟。正式压测建议采用分阶段配置:

基线验证:10 ~ 50 并发,3 ~ 5 分钟
目标高峰:按历史峰值并发或 QPS 设置,15 ~ 30 分钟
容量冗余:目标峰值 × 1.3 ~ 1.5,15 分钟
长稳测试:70% ~ 100% 峰值,4 小时以上

不要一上来直接把并发拉满。先小流量验证脚本、断言、参数化和监控,再逐级升压。压测脚本有问题时猛压,只会得到一堆很贵但没用的数据。

压测区域与执行机

截图中可以选择压测区域,例如“华南区/广州集群”,并配置执行机数量。建议:

  • 用户集中在哪个区域,就优先选择相近压测区域。
  • 如果要评估全国用户访问质量,可分别选择多个区域执行,对比网络延迟差异。
  • 当单台执行机 CPU、网络或连接数接近瓶颈时,应增加执行机数量,避免压测机先被打满。
  • 压测报告中要记录压测区域和执行机数量,否则不同批次结果不可比。

执行链路权重

压力任务中可对执行链路设置权重。多链路场景建议按真实业务占比配置:

链路 示例 权重
浏览链路 首页 → 列表 → 详情 0.60
搜索链路 首页 → 搜索 → 详情 0.20
交易链路 登录 → 详情 → 下单 0.10
用户中心链路 登录 → 用户中心 → 订单列表 0.10

权重不是拍脑袋,最好来自网关日志、埋点、APM 或历史访问统计。

9.6 使用优测压力测试工具执行 HTTP 压测的推荐流程

第 1 步:新建测试场景
- 选择“全链路”,协议选择 HTTP。

第 2 步:配置核心 API
- 录入 URL、方法、请求头、请求体、请求参数。

第 3 步:设置参数化和出参
- 从 CSV、变量或前序接口响应中生成动态参数。
- token、itemId、orderId 等字段通过出参传递。

第 4 步:配置断言
- 同时校验 HTTP 状态码、业务 code、核心返回字段。

第 5 步:编排用户链路
- 使用等待、循环、事务、并行、集合点等控制器模拟真实行为。

第 6 步:创建压力任务
- 选择用户并发或 RPS 模式,设置并发、区域、执行机、持续时间。

第 7 步:小流量冒烟
- 先用 1 ~ 10 并发验证脚本、数据、断言、监控是否正常。

第 8 步:逐级加压
- 按 30%、60%、100%、130% 峰值逐级执行。

第 9 步:分析结果
- 联合优测压测报告、服务端 APM、网关、数据库、缓存、主机监控定位瓶颈。

第 10 步:调优复测
- 保持相同场景、相同参数、相同压测区域,对比优化前后结果。

9.7 优测压测结果的分析口径

使用优测压力测试平台输出报告时,建议至少关注:

  • 链路级指标:全链路成功率、链路 P95/P99、事务耗时。
  • 接口级指标:单 API QPS、P95/P99、错误率、超时数。
  • 错误分布:HTTP 4xx/5xx、业务断言失败、连接失败、读取超时。
  • 并发与吞吐关系:并发增加后 QPS 是否线性增长,还是已经到达拐点。
  • 压测机健康度:执行机 CPU、网络、连接数是否成为瓶颈。
  • 区域差异:不同压测区域到服务端的网络延迟和失败率差异。

结论建议写成同一口径:

使用优测压力测试平台在华南区/广州集群发起全链路 HTTP 压测:
- 压测模式:用户并发模式
- 并发用户:800
- 持续时间:30 分钟
- 链路权重:浏览 60%,搜索 20%,交易 10%,用户中心 10%
- 全链路 P95:1.2s,满足 <1.5s SLA
- 核心接口 P95:登录 380ms,首页 460ms,列表 520ms,详情 410ms
- HTTP 错误率:0.04%
- 业务断言失败率:0.02%
- 性能瓶颈:列表接口在 600 并发后 P95 上升明显,数据库慢查询占比升高
- 调优建议:优化列表查询索引,增加热门列表缓存,复测 1.3 倍峰值容量

9.8 落地注意事项

  • 压测前先冒烟:先小并发跑通链路,确认变量、出参、断言正确。
  • 断言必须严格:只看 HTTP 200 会掩盖业务失败。
  • 参数必须分散:账号、ID、关键词、分页参数要动态化。
  • 写接口必须隔离:测试数据、幂等键、清理机制必须提前准备。
  • 压测区域要固定:优化前后对比必须使用同一区域、同一链路、同一流量模型。
  • 监控必须同步打开:性能指标看到的是外部表现,真正瓶颈还要看服务端、数据库、缓存和网关。
  • 不要忽略执行机瓶颈:如果压测机先满载,报告中的系统瓶颈判断会失真。
  • 保存场景版本:每次调优复测前,记录场景版本、链路权重、并发模式、压测区域和执行时长。

10. 结果分析方法

10.1 看趋势,不只看单点

一次压测至少要看这些曲线:

  • QPS / RPS
  • P50 / P90 / P95 / P99 响应时间
  • HTTP 错误率
  • 业务错误率
  • CPU / 内存 / GC
  • 数据库连接数 / 慢查询 / 锁等待
  • 缓存命中率 / Redis 延迟
  • 网关 upstream 响应时间
  • 第三方接口耗时

10.2 判断瓶颈的常见信号

现象 可能瓶颈 验证方式
QPS 上不去,CPU 很高 应用计算瓶颈 Profiling、热点函数、序列化开销
P95 飙升,CPU 不高 下游等待或连接池不足 查看 DB/Redis/HTTP 客户端连接池
5xx 增加,网关 504 后端超时 查 upstream response time 与应用日志
数据库 CPU 高,慢查询多 SQL 或索引问题 EXPLAIN、慢查询日志、索引命中率
Redis 命中率低 缓存策略问题 热 key、穿透、击穿、雪崩分析
内存持续增长 内存泄漏 Heap dump、对象增长趋势
P99 高但 P50 正常 尾延迟问题 GC、锁竞争、网络抖动、少量慢 SQL
错误集中在高峰瞬间 限流/队列/扩容不足 Spike test 与自动扩容日志

10.3 压测结论模板

建议每次压测输出固定结论:

在 800 并发、持续 30 分钟、目标流量 3,000 QPS 下:
- 实际平均 QPS:2,920
- P95 响应时间:420ms,满足 <500ms SLA
- P99 响应时间:860ms,满足 <1000ms SLA
- HTTP 错误率:0.03%,满足 <0.1% SLA
- 业务错误率:0.02%,满足 <0.1% SLA
- 应用 CPU 峰值:68%,内存稳定
- 数据库连接池使用率峰值:76%,存在一定余量
结论:当前配置可承载目标高峰流量,但数据库连接池和订单查询 SQL 接近瓶颈,建议优化后再进行 1.5 倍峰值验证。

11. HTTP 层调优建议

11.1 连接复用

问题表现:TCP 建连或 TLS 握手耗时高,短连接过多。

优化建议:

  • 开启 HTTP Keep-Alive
  • 合理配置连接池最大连接数、空闲连接数、连接存活时间
  • HTTPS 开启 TLS session resumption
  • 服务端避免过短的 keepalive timeout
  • 客户端 SDK 复用 HTTP client,不要每次请求新建 client

11.2 超时控制

超时不是越长越安全,长超时会拖垮线程和连接池。

建议分层设置:

客户端总超时:2 ~ 5 秒
网关超时:略高于后端 SLA
服务间调用超时:核心读接口 300 ~ 800ms,写接口按业务设置
数据库查询超时:核心接口建议 < 1 秒
第三方调用超时:必须设置,且要有降级方案

11.3 重试策略

错误重试会放大高峰压力,设计不好就是“自带 DDoS”。

建议:

  • 只对幂等请求重试,如 GET、可幂等 PUT
  • POST 写入类接口默认不自动重试,除非有幂等键
  • 使用指数退避和随机抖动
  • 限制最大重试次数,通常 1 ~ 2 次
  • 高峰错误率升高时,优先熔断而不是疯狂重试

11.4 响应体优化

响应体过大会直接影响下载时间、流量成本和移动端体验。

建议:

  • 开启 gzip/br 压缩
  • 列表接口只返回必要字段
  • 图片、视频等资源走 CDN,不走业务 API
  • 分页返回,避免一次返回大数组
  • 对移动端做字段裁剪
  • 使用 ETag / Last-Modified 做条件请求

11.5 缓存策略

高峰期最有效的优化,通常不是扩机器,而是少打后端。

建议:

  • 首页、配置、字典、热门列表适合缓存
  • 热点数据使用本地缓存 + Redis 多级缓存
  • 设置缓存随机过期时间,避免同一时间集体失效
  • 对空结果做短 TTL 缓存,防止缓存穿透
  • 热点 key 做拆分或本地副本,避免 Redis 单 key 压力
  • 写后读一致性要求高的场景,要明确缓存更新策略

12. 应用服务调优建议

12.1 线程池/协程池

常见问题:线程池太小导致排队,太大导致上下文切换和资源争抢。

优化方向:

  • 按 CPU 密集型和 IO 密集型分开配置线程池
  • 监控队列长度、拒绝次数、活跃线程数
  • 不要所有业务共用一个线程池
  • 关键接口单独隔离资源,避免被低优先级接口拖死

12.2 序列化与反序列化

高 QPS 下 JSON 序列化可能成为 CPU 热点。

优化方向:

  • 减少不必要字段
  • 避免重复序列化
  • 复用对象映射配置
  • 对超大响应考虑流式输出或分页
  • 检查日志中是否重复打印大对象

12.3 日志优化

高峰期 debug 日志是隐形性能杀手。

建议:

  • 生产和压测环境关闭 debug
  • 采样打印高频日志
  • 错误日志要带 trace id,但不要打印大对象和敏感信息
  • 异步日志队列要监控积压
  • 磁盘 IO 要纳入监控

12.4 限流、熔断、降级

压测不是只验证“能扛多少”,也要验证“扛不住时是否优雅”。

建议:

  • 网关按接口、用户、设备、IP 做限流
  • 核心服务对下游依赖设置熔断
  • 非核心接口支持降级,如推荐、活动弹窗、非关键统计
  • 高峰时关闭或降级低价值功能
  • 返回明确错误码,避免客户端无限重试

13. 数据库调优建议

13.1 慢查询治理

优先处理 P0/P1 接口中的高频慢 SQL。

检查项:

  • 是否命中索引
  • 是否有全表扫描
  • 是否排序、分组、分页代价过高
  • 是否返回字段过多
  • 是否 N+1 查询
  • 是否锁等待严重

13.2 索引优化

原则:为高频查询设计联合索引,不是给每个字段都建索引。

建议:

  • 按 where 条件、排序字段、过滤选择性设计联合索引
  • 避免索引失效,如函数包裹、隐式类型转换、前置模糊匹配
  • 删除无效或重复索引,降低写入成本
  • 对大表分页避免深分页,可使用游标或 last_id 翻页

13.3 连接池优化

连接池过小会排队,过大会压垮数据库。

建议:

应用总最大连接数 < 数据库最大连接数 × 70%
单实例连接池 = 可用数据库连接数 / 应用实例数

同时监控:

  • 活跃连接数
  • 等待连接数
  • 获取连接耗时
  • 连接超时次数
  • 事务耗时

14. 网关与基础设施调优建议

14.1 网关/Nginx

关注配置:

  • worker_processes / worker_connections
  • keepalive_timeout
  • upstream keepalive
  • proxy_connect_timeout / proxy_read_timeout / proxy_send_timeout
  • client_body_buffer_size
  • gzip/br 压缩
  • 限流与熔断策略

14.2 负载均衡

检查项:

  • 是否存在实例流量不均
  • 健康检查是否准确
  • 慢实例是否及时摘除
  • 会话保持是否导致热点
  • 扩容实例是否完成预热再接流量

14.3 CDN 与边缘缓存

适用对象:静态资源、配置、图片、活动页、部分匿名可缓存 API。

建议:

  • 静态资源长缓存,文件名加 hash
  • 图片使用 WebP/AVIF,按设备尺寸返回
  • 热门活动资源提前预热
  • API 缓存要谨慎处理用户态数据

15. 移动 APP 特有关注点

APP 性能差不一定全是服务端问题。HTTP 链路还受移动网络和客户端实现影响。

建议同时验证:

  • 弱网场景:3G、4G、丢包、抖动、高延迟
  • HTTPS 握手耗时
  • DNS 解析耗时和失败率
  • 客户端是否重复请求同一接口
  • 首页是否串行请求过多
  • 是否存在无用轮询
  • 是否合理使用本地缓存
  • 是否有请求取消机制,页面退出后不继续占资源

移动端链路优化方向:

  • 首页核心接口聚合,减少首屏请求数
  • 非首屏接口延迟加载
  • 静态配置本地缓存
  • 失败重试加退避,不要立刻重复打
  • 图片资源按屏幕尺寸加载

16. 推荐监控看板

压测期间至少准备 5 类看板:

16.1 HTTP 看板

  • 总 QPS
  • 各接口 QPS
  • P50/P90/P95/P99
  • 2xx/4xx/5xx 比例
  • 超时数
  • 响应体大小

16.2 应用看板

  • CPU、内存
  • 线程池/协程数
  • GC 次数和耗时
  • 错误日志数
  • 慢接口 Top N

16.3 数据库看板

  • 查询 QPS
  • 慢查询数
  • 连接数
  • 锁等待
  • Buffer/cache 命中率
  • 主从延迟

16.4 缓存看板

  • Redis QPS
  • 命中率
  • P95 延迟
  • 热 key
  • 大 key
  • 连接数

16.5 基础设施看板

  • 机器 CPU/内存/磁盘/网络
  • 网关连接数
  • 负载均衡后端状态
  • 容器重启次数
  • 自动扩容事件

17. 调优优先级建议

高优先级:立即处理

  1. P0 接口 P95/P99 超 SLA
  2. 5xx、504、连接超时
  3. 数据库慢查询和锁等待
  4. 连接池耗尽
  5. 高峰期重试风暴
  6. 缓存穿透、击穿、雪崩
  7. 单点第三方依赖拖垮主链路

中优先级:短期优化

  1. 响应体过大
  2. 首页接口过多且串行
  3. 热点数据未缓存
  4. 日志过量
  5. 网关和应用超时配置不一致
  6. 实例流量不均

长期优化:体系建设

  1. 性能基线自动化
  2. 核心接口性能预算
  3. 发布前性能回归
  4. 生产 RUM 与 APM 联动
  5. 高峰容量预测模型
  6. 自动扩缩容策略验证

18. 性能测试执行流程

第 1 步:需求确认
- 明确高峰期问题表现、核心业务链路、目标 SLA、测试环境边界

第 2 步:接口梳理
- 输出接口清单、调用关系、数据依赖、业务断言

第 3 步:基线测试
- 单接口低并发测试,建立当前性能基线

第 4 步:场景建模
- 按真实流量比例设计混合场景和 think time

第 5 步:负载测试
- 验证目标峰值和安全冗余下是否满足 SLA

第 6 步:压力/尖峰/稳定性测试
- 找到系统拐点、恢复能力和长稳问题

第 7 步:瓶颈分析
- 联合 HTTP、应用、数据库、缓存、网关指标定位瓶颈

第 8 步:调优改造
- 按优先级优化 SQL、缓存、连接池、网关、应用代码

第 9 步:复测验证
- 使用相同脚本、相同流量模型对比优化前后结果

第 10 步:沉淀机制
- 建立监控、告警、性能预算和发布前回归

19. 验收标准

一次性能优化是否完成,不看“感觉快了”,看以下条件:

  1. 压测目标 QPS 达到高峰预估的 1.3 ~ 1.5 倍。
  2. 核心接口 P95/P99 满足 SLA。
  3. HTTP 错误率和业务错误率低于阈值。
  4. 关键资源使用率有安全余量。
  5. 压力拐点明确,最大稳定承载能力有数据支撑。
  6. 尖峰流量下限流、降级、熔断策略有效。
  7. 长稳测试无明显内存泄漏、连接泄漏、性能衰减。
  8. 优化前后有同口径对比数据。
  9. 监控和告警覆盖核心链路。
  10. 发布流程中加入性能回归或性能预算校验。

20. 面向高峰期问题的推荐落地方案

如果您的 APP 或 Web 应用当前已经在高峰期表现不佳,建议按以下节奏推进:

第一阶段:3 天内完成诊断

  • 梳理 P0/P1 接口和核心链路
  • 拉取历史高峰流量、错误率、响应时间
  • 建立基础压测脚本
  • 完成单接口基线测试
  • 初步定位 Top 5 慢接口和 Top 5 错误接口

第二阶段:1 周内完成主瓶颈优化

  • 处理慢 SQL、索引、连接池问题
  • 调整网关/应用超时和连接复用
  • 对高频读接口加缓存
  • 处理响应体过大和无效字段
  • 验证 1.0 倍高峰流量稳定性

第三阶段:2 周内完成容量验证

  • 完成 1.3 ~ 1.5 倍高峰负载测试
  • 完成尖峰测试和长稳测试
  • 验证限流、熔断、降级
  • 输出容量模型和扩容建议
  • 把性能测试纳入发布门禁

21. 最终交付物清单

建议一次完整 HTTP 性能测试项目至少交付:

  1. 性能测试方案:范围、目标、场景、数据、风险。
  2. 接口清单与流量模型:接口权重、用户行为比例、think time。
  3. 压测脚本:k6/JMeter 脚本、测试数据、执行说明。
  4. 性能测试报告:结果、曲线、瓶颈、结论。
  5. 调优记录:每项优化的前后对比。
  6. 容量评估报告:最大稳定 QPS、推荐实例数、扩容策略。
  7. 监控告警方案:核心指标、阈值、责任人、应急动作。
  8. 发布性能门禁:核心接口 SLA、自动化回归、失败阻断规则。
  9. 优测平台配置留档:测试场景、执行链路、链路权重、压测模式、压测区域、执行机数量、断言规则和报告链接。

结语

HTTP 性能优化的关键不是“压到崩”,而是用数据找到系统劣化的第一现场。对于业务高峰期性能问题,建议优先从核心链路 P95/P99、错误率、连接池、慢 SQL、缓存命中率和网关超时入手。每一项优化都必须复测,只有能被数据证明的优化,才算真正完成。


本文未注明其它来源的内容,其版权归原作者所有。如需转载,请在显著位置注明出处(优测云服务平台,以及文章链接:https://utest.21kunpeng.com/home/topic/pts0629