【性能测试】17 - 性能测试入门

前言

前面 16 篇覆盖了功能测试的三个维度:Web UI 自动化验证页面功能,接口自动化验证后端逻辑,App 自动化验证移动端交互。但有一类问题这些都测不了:系统在高并发下还能不能正常工作?

  • 100 个用户同时登录,服务器会不会崩溃?
  • 商品列表接口响应时间从 200ms 涨到 5s,用户体验还行吗?
  • 大促活动开始瞬间涌入 1000 个请求,系统扛得住吗?

这些问题需要性能测试来回答。

本篇用 JMeter 对 MallLite 做接口性能测试。JMeter 是性能测试领域最常用的工具,开源免费,社区成熟。

本篇九个部分:

  1. 什么是性能测试
  2. 性能测试指标
  3. JMeter 环境搭建
  4. JMeter 核心概念
  5. 第一个测试计划:MallLite 登录接口
  6. 测试计划进阶:多接口场景
  7. 参数化与关联
  8. 测试场景设计
  9. 性能报告分析

一、什么是性能测试

1.1 性能测试的定义

功能测试验证的是"系统做对了没有",性能测试验证的是"系统做得快不快、扛不扛得住"。

复制代码
功能测试:1 个用户登录 → 返回"登录成功" → 结果正确 ✓
性能测试:100 个用户同时登录 → 都返回"登录成功" → 平均 200ms → 指标达标 ✓
性能测试:1000 个用户同时登录 → 80% 返回成功,20% 超时 → 指标不达标 ✗

1.2 性能测试的类型

类型 目的 做法
负载测试(Load) 测试系统在预期负载下的表现 逐步增加用户数,观察指标变化 100 个用户同时浏览商品
压力测试(Stress) 找到系统的极限 继续增加用户数直到系统崩溃 加到 500、1000 用户看什么时候扛不住
稳定性测试(Endurance) 测试长时间运行是否稳定 用固定负载持续运行几小时 100 个用户持续运行 4 小时
并发测试(Spike) 测试瞬间高并发 短时间内突然涌入大量请求 大促开始瞬间 1000 个请求同时到达

知识点:什么时候需要做性能测试?

复制代码
必须做:
  - 新系统上线前
  - 大促活动前(双 11、618)
  - 架构变更后(换了数据库、加了缓存、迁移到云)

建议做:
  - 接口响应变慢了,定位瓶颈
  - 数据量增长后(从 1 万条商品变成 100 万条)
  - 新增了核心功能(如支付模块)

不需要做:
  - 内部管理系统(用户少,性能不是问题)
  - 纯前端页面(性能瓶颈在后端)

1.3 性能测试流程

复制代码
第 1 步:明确目标
  系统需要支撑多少并发用户?
  接口响应时间要求是多少?
  可接受的错误率是多少?

第 2 步:选择场景
  选哪些接口测?(核心接口优先)
  每个接口的请求比例是多少?
  例:浏览商品 60%,搜索 20%,登录 10%,下单 10%

第 3 步:准备环境
  性能测试环境要跟生产环境配置一致(或按比例缩放)
  准备测试数据(数据库中有足够的数据量)

第 4 步:编写脚本
  用 JMeter 编写测试计划
  配置线程组、HTTP 请求、断言、监听器

第 5 步:执行测试
  逐步加压,记录数据
  先小规模验证脚本正确,再大规模正式测试

第 6 步:分析结果
  分析响应时间、吞吐量、错误率
  找出性能瓶颈(数据库慢?网络延迟?代码问题?)

第 7 步:优化验证
  针对瓶颈做优化
  重新测试,对比优化效果

二、性能测试指标

2.1 核心指标

指标 英文 含义
响应时间 Response Time 从发送请求到收到响应的时间 200ms
吞吐量 Throughput (TPS/QPS) 每秒处理的请求数 TPS = 500(每秒处理 500 个请求)
并发用户数 Concurrent Users 同时操作系统的用户数 100 个用户同时在线
错误率 Error Rate 失败请求占总请求的比例 0.1%(每 1000 个请求有 1 个失败)

2.2 响应时间详解

复制代码
用户感知:
  < 200ms   → 非常快(用户感觉不到延迟)
  200-500ms → 快(可以接受)
  500ms-1s  → 还行(用户能感觉到,但不烦躁)
  1-3s      → 慢(用户开始不耐烦)
  > 3s      → 很慢(用户可能离开)
  > 10s     → 超时(用户关闭页面)

性能测试中的关键值:
  平均响应时间(Average)   → 所有请求的平均值
  中位数(Median/P50)     → 50% 的请求在这个时间内完成
  90 分位(P90)           → 90% 的请求在这个时间内完成
  95 分位(P95)           → 95% 的请求在这个时间内完成
  99 分位(P99)           → 99% 的请求在这个时间内完成
  最大响应时间(Max)       → 最慢的那个请求

知识点:为什么不能只看平均值?

复制代码
假设有 10 个请求,响应时间分别是:
  100, 120, 150, 180, 200, 220, 250, 300, 500, 5000

平均值 = 702ms    ← 看起来还行
P95 = 500ms       ← 95% 的请求在 500ms 内
最大值 = 5000ms   ← 有 1 个请求用了 5 秒!

如果只看平均值,会漏掉那 1 个 5 秒的慢请求。
所以性能测试通常看 P95 或 P99,而不是平均值。

2.3 吞吐量详解

复制代码
TPS(Transactions Per Second):每秒事务数
  一个"事务"可以包含一个或多个请求
  例:一次"下单"事务 = 加购物车请求 + 创建订单请求

QPS(Queries Per Second):每秒查询数
  通常指每秒的请求数
  TPS 和 QPS 的区别:一个 TPS 可能包含多个 QPS

关系:
  如果每个事务只包含 1 个请求:TPS = QPS
  如果每个事务包含 3 个请求:TPS = QPS / 3

2.4 错误率详解

复制代码
可接受的错误率:
  核心接口(登录、下单、支付):0%(不允许出错)
  一般接口(商品列表、搜索):  < 0.1%
  非核心接口(推荐、统计):    < 1%

常见的错误原因:
  连接超时     → 服务器来不及处理,队列满了
  响应超时     → 接口太慢,超过客户端等待时间
  500 错误     → 服务器内部异常(代码 bug 或资源不足)
  连接被拒绝   → 服务器主动拒绝新连接(达到最大连接数)

2.5 一份性能测试报告需要包含什么

复制代码
1. 测试环境描述
   服务器配置、数据库配置、网络环境

2. 测试场景描述
   测了哪些接口、并发数、持续时间

3. 测试结果数据
   ┌─────────────┬──────────┬──────────┬──────────┬──────────┐
   │ 接口         │ 平均RT    │ P95 RT   │ TPS      │ 错误率    │
   ├─────────────┼──────────┼──────────┼──────────┼──────────┤
   │ 登录         │ 180ms    │ 350ms    │ 200      │ 0%       │
   │ 商品列表     │ 120ms    │ 280ms    │ 500      │ 0%       │
   │ 创建订单     │ 450ms    │ 800ms    │ 100      │ 0.1%     │
   └─────────────┴──────────┴──────────┴──────────┴──────────┘

4. 结论和建议
   哪些达标、哪些不达标、瓶颈在哪、怎么优化

三、JMeter 环境搭建

3.1 为什么用 JMeter

维度 JMeter LoadRunner Locust
费用 免费开源 商业(很贵) 免费开源
学习难度 中等 较高 较低(Python)
协议支持 HTTP、JDBC、FTP、SMTP 等 全面 主要是 HTTP
GUI 有图形界面 有图形界面 Web 界面
分布式 支持 支持 支持
社区 非常成熟 一般 活跃
适用场景 接口性能测试为主 企业级全面性能测试 接口性能测试

JMeter 是性能测试领域使用最广泛的开源工具,适合入门学习。

3.2 安装步骤

第 1 步:确认 Java 已安装

JMeter 是 Java 开发的,需要 JDK。

powershell 复制代码
java -version
# 如果第 14 篇已经装过 JDK,这里应该有输出

第 2 步:下载 JMeter

复制代码
浏览器打开 https://jmeter.apache.org/download_jmeter.cgi
下载 apache-jmeter-5.x.zip(Binary 版本)
解压到一个目录,如 D:\tools\apache-jmeter-5.x

第 3 启动 JMeter

powershell 复制代码
cd D:\tools\apache-jmeter-5.x\bin
jmeter.bat

JMeter 会打开图形界面(GUI 模式),看起来像一个树状结构的配置工具。

知识点:JMeter 的两种模式

复制代码
GUI 模式(图形界面):
  用来设计和调试测试计划
  不适合运行大规模测试(GUI 本身消耗资源)

Non-GUI 模式(命令行):
  用来运行正式的性能测试
  命令:jmeter -n -t test_plan.jmx -l result.jtl -e -o report/
  消耗资源少,结果更准确

正确的工作流程:
  1. 用 GUI 模式设计测试计划
  2. 保存为 .jmx 文件
  3. 用 Non-GUI 模式运行测试
  4. 用 GUI 模式或 HTML 报告查看结果

3.3 设置中文界面

JMeter 默认是英文界面。改为中文:

复制代码
菜单栏 → Options → Choose Language → Chinese (Simplified)

设置后界面会变成中文。


四、JMeter 核心概念

4.1 测试计划的结构

JMeter 的测试计划是一棵树:

复制代码
测试计划(Test Plan)          ← 顶层容器
├── 线程组(Thread Group)     ← 模拟用户
│   ├── 配置元件              ← 全局配置(如 HTTP 请求默认值)
│   ├── 前置处理器             ← 请求发送前的操作(如参数化)
│   ├── 取样器(Sampler)      ← 实际发送的请求(如 HTTP 请求)
│   ├── 后置处理器             ← 请求发送后的操作(如提取响应数据)
│   ├── 断言(Assertion)      ← 验证响应是否正确
│   └── 监听器(Listener)     ← 查看结果和图表
└── 线程组 2...               ← 可以有多个线程组

4.2 各组件的作用

线程组(Thread Group)

复制代码
线程组 = 一组虚拟用户

配置项:
  线程数(Number of Threads)= 100    → 模拟 100 个用户
  启动时间(Ramp-Up Period)= 10s     → 10 秒内启动完 100 个用户
  循环次数(Loop Count)= 5           → 每个用户执行 5 次

含义:
  100 个用户,10 秒内陆续启动,每个用户执行 5 次请求
  总请求数 = 100 × 5 = 500

  ┌─── 第 1 秒:10 个用户开始 ───┐
  ├─── 第 2 秒:10 个用户开始   ───┤
  ├─── ...                       ───┤
  └─── 第 10 秒:最后 10 个用户 ───┘
  → 100 个用户全部就绪

知识点:Ramp-Up 的重要性

复制代码
如果 Ramp-Up = 0:
  100 个用户同时启动 → 瞬间涌入 100 个请求 → 不真实

如果 Ramp-Up = 100:
  100 个用户,100 秒内启动 → 每秒启动 1 个 → 太温和

一般设为"线程数 / 10":
  100 个用户,Ramp-Up = 10 → 每秒启动 10 个 → 比较真实

取样器(Sampler)

复制代码
取样器 = 一个具体的请求

HTTP 请求取样器:
  协议:http
  服务器:localhost
  端口:8000
  方法:POST
  路径:/api/user/login
  请求体:{"username": "admin", "password": "admin123"}

断言(Assertion)

复制代码
断言 = 验证响应是否符合预期

响应断言:
  检查响应中是否包含 "登录成功"
  如果不包含,该请求标记为失败

状态码断言:
  检查 HTTP 状态码是否为 200

监听器(Listener)

复制代码
监听器 = 查看测试结果的工具

查看结果树     → 每个请求的详细信息(调试用)
聚合报告       → 统计数据(平均值、P95、TPS、错误率)
响应时间图     → 响应时间的趋势图
TPS 图         → 吞吐量的趋势图

配置元件

复制代码
HTTP 请求默认值:
  设置所有 HTTP 请求的公共参数(服务器地址、端口)
  避免每个请求都重复填写

定时器(Timer)

复制代码
定时器 = 请求之间的等待时间(模拟用户"思考时间")

固定定时器:每次请求前等待 1000ms
高斯随机定时器:等待 500-1500ms 之间的随机时间

知识点:为什么要加定时器?
  真实用户不会连续不停地发请求。
  用户看完商品列表 → 思考几秒 → 点击详情 → 看几秒 → 加购物车
  定时器模拟这个"思考时间",让测试更接近真实场景。

五、第一个测试计划:MallLite 登录接口

5.1 目标

对 MallLite 的登录接口做简单的并发测试:50 个用户同时登录,观察响应时间和错误率。

5.2 创建步骤

第 1 步:新建测试计划

复制代码
打开 JMeter → 菜单 → 文件 → 新建
左侧面板出现"测试计划"

第 2 步:添加 HTTP 请求默认值

复制代码
右键测试计划 → 添加 → 配置元件 → HTTP 请求默认值

填写:
  协议:http
  服务器名称或 IP:localhost
  端口号:8000

知识点:HTTP 请求默认值的作用

所有 HTTP 请求都会继承这些默认值,不用每个请求都写一遍 localhost:8000。如果要换测试环境,只改这一处。

第 3 步:添加线程组

复制代码
右键测试计划 → 添加 → 线程(用户)→ 线程组

填写:
  线程数(用户数):50
  启动时间(秒):5
  循环次数:10

含义:50 个虚拟用户,5 秒内启动,每个用户执行 10 次登录。总请求数 = 50 × 10 = 500。

第 4 步:添加 HTTP 请求

复制代码
右键线程组 → 添加 → 取样器 → HTTP 请求

填写:
  名称:登录接口
  方法:POST
  路径:/api/user/login
  
  消息体数据(Body Data):
  {
    "username": "admin",
    "password": "admin123"
  }

  HTTP 请求头(需要先添加 HTTP 信息头管理器):
  Content-Type: application/json

第 5 步:添加 HTTP 信息头管理器

复制代码
右键线程组 → 添加 → 配置元件 → HTTP 信息头管理器

添加:
  名称:Content-Type
  值:application/json

知识点:为什么需要设置 Content-Type?

MallLite 的接口是 RESTful JSON 格式。如果不设置 Content-Type: application/json,服务器可能无法解析请求体。

第 6 步:添加响应断言

复制代码
右键 HTTP 请求 → 添加 → 断言 → 响应断言

填写:
  测试字段:响应文本
  模式匹配规则:包括
  测试模式:登录成功

如果响应中不包含"登录成功",该请求标记为失败。

第 7 步:添加监听器

复制代码
右键线程组 → 添加 → 监听器 → 查看结果树(调试用)
右键线程组 → 添加 → 监听器 → 聚合报告(正式数据)
右键线程组 → 添加 → 监听器 → 用表格查看结果

5.3 调试运行

复制代码
第 1 步:先确认 MallLite 正在运行
  cd mall-lite && python run.py

第 2 步:在 JMeter 中点击绿色三角形 ▶ 按钮(启动)
  注意:会弹出提示"是否保存",选择保存到一个 .jmx 文件

第 3 步:查看"查看结果树"
  绿色 ✅ → 请求成功
  红色 ❌ → 请求失败(查看响应数据排查原因)

5.4 正式运行

调试通过后,用命令行运行(GUI 模式消耗资源,影响结果准确性):

powershell 复制代码
cd D:\tools\apache-jmeter-5.x\bin

# 命令行运行
jmeter -n -t test_plans/login_test.jmx -l reports/login_result.jtl -e -o reports/login_report

# 参数说明:
#   -n              Non-GUI 模式
#   -t test.jmx     测试计划文件
#   -l result.jtl   结果数据文件
#   -e              生成 HTML 报告
#   -o report/      HTML 报告输出目录

运行完成后,打开 reports/login_report/index.html 查看报告。

5.5 读取聚合报告

复制代码
聚合报告中的关键列:

标签          → 接口名称(登录接口)
样本          → 总请求数(500)
平均值        → 平均响应时间(ms)
中位数        → P50 响应时间
90% 百分位    → P90 响应时间
95% 百分位    → P95 响应时间
99% 百分位    → P99 响应时间
最小值        → 最快的响应时间
最大值        → 最慢的响应时间
异常%         → 错误率
吞吐量        → TPS(每秒处理请求数)

六、测试计划进阶:多接口场景

6.1 为什么测多接口

真实用户不会只调一个接口。一个典型的用户行为是:

复制代码
登录 → 浏览商品列表 → 查看商品详情 → 加购物车 → 创建订单

性能测试需要模拟这个完整流程,因为接口之间会共享资源(连接池、Session、数据库连接),单独测一个接口看不出问题。

6.2 创建多接口测试计划

在同一个线程组下添加多个 HTTP 请求,按用户操作顺序排列:

复制代码
线程组(50 用户,Ramp-Up 10s,循环 10 次)
├── HTTP 请求默认值(localhost:8000)
├── HTTP 信息头管理器(Content-Type: application/json)
│
├── HTTP 请求 1:登录
│   POST /api/user/login
│   Body: {"username": "admin", "password": "admin123"}
│   └── 后置处理器:JSON 提取器(提取 token)
│
├── 定时器(固定定时器 1000ms,模拟"思考")
│
├── HTTP 请求 2:获取商品列表
│   GET /api/product/list?page=1&pageSize=20
│   HTTP 请求头:Authorization: ${token}
│
├── 定时器(固定定时器 2000ms)
│
├── HTTP 请求 3:获取商品详情
│   GET /api/product/detail/1
│   HTTP 请求头:Authorization: ${token}
│
├── 定时器(固定定时器 1000ms)
│
├── HTTP 请求 4:添加购物车
│   POST /api/cart/add
│   Body: {"productId": 1, "quantity": 1}
│   HTTP 请求头:Authorization: ${token}
│
└── 聚合报告

知识点:后置处理器和关联

登录接口返回的 token 需要传给后续请求。用 JSON 提取器从登录响应中提取 token,存到变量 ${token} 中,后续请求通过 ${token} 引用。

这跟接口自动化中"从登录响应提取 token 给后续接口用"是同一个思路。


七、参数化与关联

7.1 参数化

如果 50 个用户都用同一个账号登录,服务器只维护一个 Session,不能真实反映并发压力。参数化让每个虚拟用户用不同的账号。

方式 1:CSV 数据文件设置

复制代码
第 1 步:创建 CSV 文件 test_data/users.csv
  admin,admin123
  user1,password1
  user2,password2
  user3,password3
  ...

第 2 步:在 JMeter 中添加 CSV 数据文件设置
  右键线程组 → 添加 → 配置元件 → CSV 数据文件设置
  
  文件名:test_data/users.csv
  变量名:username,password
  分隔符:,
  遇到文件结束符是否再次循环:True

第 3 步:在 HTTP 请求中引用变量
  Body: {"username": "${username}", "password": "${password}"}

知识点:CSV 参数化的工作方式

复制代码
线程 1 → 读第 1 行 → username=admin, password=admin123
线程 2 → 读第 2 行 → username=user1, password=password1
线程 3 → 读第 3 行 → username=user2, password=password2
...
线程 50 → 读第 50 行 → ...
线程 51 → 再次从第 1 行开始(如果设置了循环)

方式 2:函数助手

复制代码
JMeter 菜单 → 工具 → 函数助手对话框

常用函数:
  __Random(1,1000)     → 生成 1-1000 的随机数
  __RandomString(8)    → 生成 8 位随机字符串
  __time(yyyyMMdd)     → 当前日期
  __UUID               → 生成唯一 ID

7.2 关联

关联是指从上一个请求的响应中提取数据,传给下一个请求。

最常见的场景:登录 → 提取 token → 后续请求带 token

复制代码
第 1 步:在"登录"请求下添加"JSON 提取器"
  右键 HTTP 请求(登录)→ 添加 → 后置处理器 → JSON 提取器
  
  变量名:token
  JSON 路径表达式:$.data.token
  匹配数字:1

第 2 步:在后续请求中引用
  HTTP 请求头管理器中添加:
  Authorization: Bearer ${token}

知识点:JSON 提取器的 JSONPath 表达式

复制代码
MallLite 登录响应:
{
  "code": 200,
  "message": "登录成功",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiJ9...",
    "username": "admin"
  }
}

JSONPath 表达式:
  $.data.token         → 提取 token 值
  $.data.username      → 提取 username
  $.code               → 提取 code
  $.data.items[0].id   → 提取列表中第一个商品的 id

这跟接口自动化中 Extractor 的思路完全一样:

复制代码
接口自动化:Extractor.get(resp.json(), "data.token")
JMeter:    JSON 提取器 → $.data.token → ${token}

7.3 定时器

复制代码
固定定时器(Constant Timer):
  每次请求前等待固定时间
  例:1000ms(模拟用户每秒操作一次)

高斯随机定时器(Gaussian Random Timer):
  等待时间在一定范围内随机
  偏差 100ms,固定延迟 300ms
  → 实际等待 200-400ms 之间的随机值

统一随机定时器(Uniform Random Timer):
  最小 500ms,最大 1500ms
  → 实际等待 500-1500ms 之间的随机值

知识点:什么时候不加定时器?
  压力测试(Stress Test)中通常不加定时器。
  因为压力测试的目的是找到系统极限,
  要求尽可能高的请求频率。
  负载测试(Load Test)才需要模拟真实用户的"思考时间"。

八、测试场景设计

8.1 场景 1:基准测试

复制代码
目的:了解系统在低负载下的基本性能
配置:
  线程数:10
  Ramp-Up:5s
  循环次数:100
  总请求数:1000

预期结果:
  响应时间 < 200ms
  错误率 = 0%
  TPS 作为基准参考

8.2 场景 2:负载测试

复制代码
目的:测试系统在预期负载下的表现
配置(逐步加压):
  阶段 1:10 用户,持续 1 分钟
  阶段 2:30 用户,持续 1 分钟
  阶段 3:50 用户,持续 1 分钟
  阶段 4:80 用户,持续 1 分钟
  阶段 5:100 用户,持续 1 分钟

观察:
  随着用户增加,响应时间怎么变化?
  TPS 是不是线性增长?
  哪个用户数级别开始出现错误?

知识点:用"阶梯线程组"实现逐步加压

复制代码
JMeter 中添加"阶梯线程组"插件(Stepping Thread Group):

  This group will start 100 threads  → 最终 100 个用户
  First, wait for 0 seconds          → 不等待,直接开始
  Then start 10 threads              → 第一批 10 个用户
  Next, add 10 threads every 30 seconds  → 每 30 秒增加 10 个
  Using ramp-up of 5 seconds         → 每批 5 秒内启动
  Then hold load for 60 seconds      → 全部启动后持续 1 分钟
  Finally, stop 10 threads every 10 seconds  → 每 10 秒减少 10 个

8.3 场景 3:压力测试

复制代码
目的:找到系统的极限(什么时候崩溃)
配置:
  线程数:逐步增加到 200、500、1000
  每个级别持续 5 分钟

观察:
  什么时候响应时间超过 3 秒?
  什么时候错误率超过 5%?
  什么时候服务器 CPU 达到 100%?
  服务器崩溃前的 TPS 是多少?

知识点:压力测试的"拐点"
  TPS 曲线通常呈现:
    前期:用户增加 → TPS 线性增长
    中期:用户继续增加 → TPS 增长变缓(到达瓶颈)
    后期:用户再增加 → TPS 下降 + 错误率上升(过载)
  
  拐点就是系统容量的上限

8.4 场景 4:稳定性测试

复制代码
目的:长时间运行是否稳定(检测内存泄漏等)
配置:
  线程数:50(预期负载)
  持续时间:4 小时(或 8 小时、24 小时)

观察:
  响应时间是否随时间增长?(可能内存泄漏)
  TPS 是否稳定?
  是否有间歇性错误?
  服务器内存使用是否持续增长?

知识点:为什么稳定性测试要跑这么久?
  某些问题只在长时间运行后才暴露:
    内存泄漏:内存使用量持续增长,直到 OOM
    连接池耗尽:数据库连接没有正确释放
    文件句柄泄漏:打开了文件没关闭
    缓存过期:缓存失效后查询变慢
  跑 10 分钟看不出这些问题,至少要跑几小时。

8.5 场景 5:混合场景

复制代码
目的:模拟真实用户的混合操作
配置(一个线程组中多个请求,按比例分布):

  浏览商品列表(60%)→ HTTP 请求:GET /api/product/list
  搜索商品(20%)    → HTTP 请求:GET /api/product/list?keyword=iPhone
  登录(10%)        → HTTP 请求:POST /api/user/login
  下单(10%)        → HTTP 请求:POST /api/order/create

  用"吞吐量控制器"控制比例:
  右键线程组 → 添加 → 逻辑控制器 → 吞吐量控制器
    百分比模式:60(浏览商品)
    百分比模式:20(搜索)
    百分比模式:10(登录)
    百分比模式:10(下单)

8.6 场景设计原则

复制代码
原则 1:先基准,后加压
  先用小负载确认脚本正确,再逐步加大负载

原则 2:一次只变一个变量
  同时改线程数和循环次数,不知道是哪个因素导致的性能变化

原则 3:模拟真实场景
  加定时器(模拟用户思考时间)
  用参数化(不同用户用不同数据)
  用混合场景(不同操作按比例分布)

原则 4:关注关键指标
  不是所有接口都要测,优先测核心接口
  不是 TPS 越高越好,要满足响应时间要求

原则 5:环境一致性
  性能测试环境的配置要跟生产环境一致(或按比例缩放)
  测试数据量要跟生产环境接近

九、性能报告分析

9.1 聚合报告解读

复制代码
┌─────────────┬───────┬────────┬────────┬────────┬────────┬───────┬───────┐
│ 标签         │ 样本   │ 平均值  │ P95    │ P99    │ 最大值  │ 异常%  │ 吞吐量 │
├─────────────┼───────┼────────┼────────┼────────┼────────┼───────┼───────┤
│ 登录接口     │ 500   │ 180ms  │ 350ms  │ 500ms  │ 1200ms │ 0%    │ 200/s │
│ 商品列表     │ 500   │ 120ms  │ 280ms  │ 420ms  │ 900ms  │ 0%    │ 350/s │
│ 商品详情     │ 500   │ 80ms   │ 180ms  │ 300ms  │ 600ms  │ 0%    │ 400/s │
│ 添加购物车   │ 500   │ 150ms  │ 320ms  │ 480ms  │ 1100ms │ 0%    │ 250/s │
│ 创建订单     │ 500   │ 450ms  │ 800ms  │ 1200ms │ 3000ms │ 0.2%  │ 100/s │
├─────────────┼───────┼────────┼────────┼────────┼────────┼───────┼───────┤
│ 总计         │ 2500  │ 196ms  │ 420ms  │ 680ms  │ 3000ms │ 0.04% │       │
└─────────────┴───────┴────────┴────────┴────────┴────────┴───────┴───────┘

分析:
  ✓ 登录、商品列表、商品详情响应时间在 200ms 以内(优秀)
  ⚠ 创建订单 P95 = 800ms(需要关注)
  ⚠ 创建订单最大值 = 3000ms(有慢请求)
  ⚠ 创建订单有 0.2% 错误率(需要排查)
  ✓ 整体错误率 0.04%(可接受)

9.2 性能瓶颈判断

现象 可能的瓶颈 优化方向
响应时间长,CPU 低 数据库慢查询、外部接口调用慢 加索引、加缓存、异步调用
响应时间长,CPU 高 代码逻辑复杂、计算密集 优化算法、减少计算
TPS 不增长,连接数到上限 连接池太小 增大连接池
内存持续增长 内存泄漏 排查代码中的内存泄漏
错误率高,日志报连接超时 服务器过载 增加服务器、加负载均衡

知识点:怎么看服务器的资源使用情况?

复制代码
Linux 服务器:
  top              → CPU 和内存使用
  vmstat 1         → CPU、内存、IO 详细信息
  iostat -x 1      → 磁盘 IO
  netstat -an | grep ESTABLISHED | wc -l  → 当前连接数

Windows 服务器:
  任务管理器 → 性能 tab
  资源监视器

数据库:
  慢查询日志
  SHOW PROCESSLIST  → 当前正在执行的查询
  EXPLAIN SELECT... → 查看查询执行计划

9.3 常见优化手段

优化方向 具体措施
数据库优化 加索引、优化 SQL、读写分离、分库分表
缓存 热点数据用 Redis 缓存(如商品列表)
代码优化 减少循环中的数据库查询、批量操作
连接池 增大数据库连接池、HTTP 连接池
异步处理 耗时操作用消息队列异步执行
负载均衡 增加服务器节点,分摊请求
CDN 静态资源(图片、JS、CSS)用 CDN 加速

9.4 性能测试结果的呈现

复制代码
写一份性能测试报告,包含:

1. 测试概述
   测试目的、测试时间、测试环境

2. 测试场景
   并发用户数、持续时间、接口列表、参数化策略

3. 测试结果
   聚合报告数据(表格)
   响应时间趋势图
   TPS 趋势图
   错误率统计

4. 结论
   哪些达标、哪些不达标
   瓶颈在哪
   优化建议

5. 附录
   服务器资源监控截图
   数据库慢查询日志
   JMeter 测试计划文件

十、今日成果

  • 讲解了性能测试的定义、类型和完整流程
  • 掌握了核心指标:响应时间(P90/P95/P99)、TPS、错误率
  • 搭建了 JMeter 环境,了解了 GUI 和 Non-GUI 两种模式
  • 理解了 JMeter 核心概念:线程组、取样器、断言、监听器、定时器
  • 编写了第一个测试计划:MallLite 登录接口并发测试
  • 设计了多接口场景:登录 → 商品列表 → 商品详情 → 加购 → 下单
  • 掌握了参数化(CSV)和关联(JSON 提取器)的用法
  • 设计了 5 种测试场景:基准、负载、压力、稳定性、混合
  • 学会了性能报告的分析方法和瓶颈判断

十一、下篇预告

18 - 项目收尾与企业落地

最后一篇,把前面 17 篇的内容串起来:完整项目结构回顾、CI/CD 集成、测试策略设计、企业级最佳实践、简历和面试指导。


性能测试篇完成。下一篇:项目收尾与企业落地(18/18)。

相关推荐
wuhuhuan2 小时前
Case Generator 测试自动化平台
python·测试工具·自动化
星核0penstarry1 天前
ToolGrad:把数据生成倒过来,工具调用样本通过率提到 99.8%
人工智能·测试工具·llm·函数调用·数据合成·文本调用
测试19982 天前
Jmeter接口自动化测试:Jmeter变量的使用
自动化测试·软件测试·测试工具·jmeter·职场和发展·测试用例·接口测试
Tinyfacture3 天前
postman抓取登录鉴权码token及设置全局变量
测试工具·postman
川石课堂软件测试3 天前
涨薪技术|Prometheus之HTTP API中使用PromQL
网络协议·测试工具·jmeter·http·单元测试·postman·prometheus
x10n94 天前
Postman 汉化完整指南
测试工具·lua·postman
yxlalm4 天前
4.1 JMeter 压测工具使用
jmeter
Luminbox紫创测控5 天前
一文读懂:准直太阳模拟器如何检测汽车AR-HUD阳光倒灌
测试工具·汽车·ar·安全性测试·太阳光模拟器·测试标准·阳光倒灌