面向 HTTP 协议的性能压测与调优指南 | 优测全链路压力测试平台
适用场景:APP/小程序/Web应用在高峰期出现接口变慢、页面加载等待、超时、错误率升高、CPU/内存/数据库连接吃紧等问题。
测试对象:服务后台后端 HTTP/HTTPS API、网关、鉴权服务、业务服务、缓存、数据库、第三方依赖链路。
目标:建立可复现、可量化、可持续的 HTTP 性能测试体系,定位高峰期瓶颈,并形成可验证的调优闭环。
1. 性能测试先讲结论:不要直接“猛压”
高峰期性能不佳,不能只靠一次大并发压测判断问题。正确做法是:
- 先建基线:确认当前单接口、核心链路、正常流量下的响应时间、吞吐、错误率。
- 再建模型:根据真实高峰流量、用户行为、接口占比设计压测场景。
- 逐级加压:从基准负载到峰值负载,再到极限负载,观察拐点。
- 定位瓶颈:结合客户端指标、HTTP 指标、应用指标、中间件指标、数据库指标一起分析。
- 调优验证:每次只改一类关键变量,做前后对比,证明优化有效。
性能测试不是“看服务器能不能扛住”,而是回答四个问题:
- 高峰期到底慢在哪里?
- 当前系统稳定承载能力是多少?
- 超过多少流量会开始劣化?
- 做哪些优化能以最小成本换来最大收益?
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 节点至少应配置以下内容:
- API 描述:命名要能看懂业务含义,不建议只叫 API1、API2。推荐命名为“登录接口”“首页聚合接口”“商品列表接口”“订单提交接口”。
- 请求 URL:使用测试环境或预发环境域名,生产压测必须经过审批和限流保护。
- 请求方法:根据接口实际行为选择 GET、POST、PUT、DELETE 等。
- 协议类型:HTTP/HTTPS。HTTPS 场景要额外关注 TLS 握手和连接复用。
- 请求头:配置
Content-Type、Authorization、设备标识、APP 版本、渠道、灰度标识等。 - 请求体/请求参数:参数要动态化,避免所有虚拟用户请求同一个资源导致结果失真。
- 出参定义:登录接口提取 token,列表接口提取 itemId,创建订单接口提取 orderId,供后续接口引用。
- 请求结果断言:必须同时校验 HTTP 状态码和业务字段。例如 HTTP 200 且
code=0才算成功。 - 前置处理器:适合处理签名、时间戳、随机数、加密参数、测试数据初始化。
- 后置处理器:适合清理临时数据、记录关键字段、转换响应结果。
- 高级配置:统一设置超时时间、重定向、连接策略,避免默认配置与生产真实行为不一致。
示例配置口径:
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. 调优优先级建议
高优先级:立即处理
- P0 接口 P95/P99 超 SLA
- 5xx、504、连接超时
- 数据库慢查询和锁等待
- 连接池耗尽
- 高峰期重试风暴
- 缓存穿透、击穿、雪崩
- 单点第三方依赖拖垮主链路
中优先级:短期优化
- 响应体过大
- 首页接口过多且串行
- 热点数据未缓存
- 日志过量
- 网关和应用超时配置不一致
- 实例流量不均
长期优化:体系建设
- 性能基线自动化
- 核心接口性能预算
- 发布前性能回归
- 生产 RUM 与 APM 联动
- 高峰容量预测模型
- 自动扩缩容策略验证
18. 性能测试执行流程
第 1 步:需求确认
- 明确高峰期问题表现、核心业务链路、目标 SLA、测试环境边界
第 2 步:接口梳理
- 输出接口清单、调用关系、数据依赖、业务断言
第 3 步:基线测试
- 单接口低并发测试,建立当前性能基线
第 4 步:场景建模
- 按真实流量比例设计混合场景和 think time
第 5 步:负载测试
- 验证目标峰值和安全冗余下是否满足 SLA
第 6 步:压力/尖峰/稳定性测试
- 找到系统拐点、恢复能力和长稳问题
第 7 步:瓶颈分析
- 联合 HTTP、应用、数据库、缓存、网关指标定位瓶颈
第 8 步:调优改造
- 按优先级优化 SQL、缓存、连接池、网关、应用代码
第 9 步:复测验证
- 使用相同脚本、相同流量模型对比优化前后结果
第 10 步:沉淀机制
- 建立监控、告警、性能预算和发布前回归
19. 验收标准
一次性能优化是否完成,不看“感觉快了”,看以下条件:
- 压测目标 QPS 达到高峰预估的 1.3 ~ 1.5 倍。
- 核心接口 P95/P99 满足 SLA。
- HTTP 错误率和业务错误率低于阈值。
- 关键资源使用率有安全余量。
- 压力拐点明确,最大稳定承载能力有数据支撑。
- 尖峰流量下限流、降级、熔断策略有效。
- 长稳测试无明显内存泄漏、连接泄漏、性能衰减。
- 优化前后有同口径对比数据。
- 监控和告警覆盖核心链路。
- 发布流程中加入性能回归或性能预算校验。
20. 面向高峰期问题的推荐落地方案
如果您的 APP 或 Web 应用当前已经在高峰期表现不佳,建议按以下节奏推进:
第一阶段:3 天内完成诊断
- 梳理 P0/P1 接口和核心链路
- 拉取历史高峰流量、错误率、响应时间
- 建立基础压测脚本
- 完成单接口基线测试
- 初步定位 Top 5 慢接口和 Top 5 错误接口
第二阶段:1 周内完成主瓶颈优化
- 处理慢 SQL、索引、连接池问题
- 调整网关/应用超时和连接复用
- 对高频读接口加缓存
- 处理响应体过大和无效字段
- 验证 1.0 倍高峰流量稳定性
第三阶段:2 周内完成容量验证
- 完成 1.3 ~ 1.5 倍高峰负载测试
- 完成尖峰测试和长稳测试
- 验证限流、熔断、降级
- 输出容量模型和扩容建议
- 把性能测试纳入发布门禁
21. 最终交付物清单
建议一次完整 HTTP 性能测试项目至少交付:
- 性能测试方案:范围、目标、场景、数据、风险。
- 接口清单与流量模型:接口权重、用户行为比例、think time。
- 压测脚本:k6/JMeter 脚本、测试数据、执行说明。
- 性能测试报告:结果、曲线、瓶颈、结论。
- 调优记录:每项优化的前后对比。
- 容量评估报告:最大稳定 QPS、推荐实例数、扩容策略。
- 监控告警方案:核心指标、阈值、责任人、应急动作。
- 发布性能门禁:核心接口 SLA、自动化回归、失败阻断规则。
- 优测平台配置留档:测试场景、执行链路、链路权重、压测模式、压测区域、执行机数量、断言规则和报告链接。
结语
HTTP 性能优化的关键不是“压到崩”,而是用数据找到系统劣化的第一现场。对于业务高峰期性能问题,建议优先从核心链路 P95/P99、错误率、连接池、慢 SQL、缓存命中率和网关超时入手。每一项优化都必须复测,只有能被数据证明的优化,才算真正完成。
本文未注明其它来源的内容,其版权归原作者所有。如需转载,请在显著位置注明出处(优测云服务平台,以及文章链接:https://utest.21kunpeng.com/home/topic/pts0629)
