上周有个朋友拿着他们刚上线的订单接口来找我,说测试环境点了上百次都挺顺,一上生产就零星超时,日志里还看不出名堂。我问他压过没有,他说拿 Postman 手动跑了二十几个请求,看着响应都挺快。这就是典型的把“功能验证”当成了“压力测试”。接口能不能用是一回事,扛不扛得住真实流量是另一回事。后来我们用 Locust 压了一轮,发现是数据库连接池太小,并发一上来线程全堵在拿连接那一步。改完配置再压,QPS 从原先卡在 200 出头直接抬到了 1600 上下。这类问题,靠点点点是永远发现不了的。
这篇内容我想围绕压力测试、QPS 以及 Locust 这个工具,把我这些年做压测的整套思路和实操细节摊开讲。会讲清楚 QPS 到底指什么、它和 TPS、并发数、响应时间之间怎么换算,会讲一套完整的压力测试方案怎么设计,也会把 Locust 从装环境到写脚本、再到分布式压测和结果解读的全过程走一遍。文章里既有已经在做后端测试的同行可以直接抄的脚本,也有刚接触性能测试、想知道接口压力测试怎么测的新人能看懂的基础解释。工具对比、参数计算、踩过的坑、排查套路我都会写进去,尽量让你看完就能上手干。
1. 先把 QPS 这件事彻底说明白
1.1 QPS 到底指的是什么
QPS,全称 Queries Per Second,每秒查询数。字面意思很简单:一秒钟系统能处理多少个请求。但真正做过压测的人都知道,这个数字如果脱离上下文单独拿出来说,基本没意义。同样一个接口,我在本机单进程压是 3000 QPS,在四台压测机分布式压是 12000 QPS,你说它到底是 3000 还是 12000?所以谈 QPS 一定要带上四个坐标:被测对象是谁、请求长什么样、测试环境什么规格、压测端有几台机器。
很多人第一次接触这个词,会下意识把它和“系统的能力上限”划等号,其实不是。QPS 是某个特定条件下测出来的一个观测值,它反映的是“在当前这个请求模型和资源配比下,系统每秒能成功返回多少响应”。请求体大小、是否走缓存、是否命中索引、后端有没有下游依赖,任何一个变量变了,这个值都会跳。我做压测有个习惯,出报告的时候永远把 QPS 和“当时的请求模型”绑在一起写,不然过两周回头看,自己都不记得那个数字是怎么来的。
还有一个容易混淆的点:QPS 统计的是“成功返回”的请求,还是“发出去”的请求。这两个差别很大。一个接口如果 40% 的请求返回 500,你把它算进 QPS 里,数字看着很漂亮,其实是自欺欺人。Locust 在统计时会区分总请求数和失败数,RPS 那栏是包含失败在内的总吞吐,真正要看的是成功请求的吞吐量,这个后面讲结果解读的时候我还会专门说。
1.2 QPS 和 TPS、并发数、响应时间到底怎么换算
这是被问得最多的一个问题。先给结论:在理想情况下,QPS ≈ 并发数 ÷ 平均响应时间(秒)。举个数:你开了 100 个并发用户,接口平均响应时间是 50 毫秒,也就是 0.05 秒,那 QPS ≈ 100 ÷ 0.05 = 2000。这个公式来自排队论里的利特尔法则(Little's Law),原式是 并发数 = 吞吐量 × 响应时间,变形一下就得到了上面那个。
理解这个公式,你就能明白两件特别重要的事。第一,想提高 QPS,要么加并发,要么降响应时间,而加并发往往是有限度的,因为资源是有限的。第二,当一个系统到达瓶颈后,你继续加并发,响应时间会等比上升,QPS 却原地不动甚至往下掉——这就是性能测试里说的“拐点”。压测的核心目的之一,就是找到这个拐点。
那 TPS 又是什么?TPS,Transactions Per Second,每秒事务数。它和 QPS 的区别在于“事务”的粒度。一个事务可能包含多个请求,比如下单这个业务动作,后台要调创建订单接口、扣库存接口、发消息接口,三个请求合起来算一个事务。所以如果是单接口压测,QPS 和 TPS 数值上基本重合;如果是业务链路压测,一个 TPS 可能对应好几个 QPS。做链路压测的时候,我通常两个指标都盯:TPS 反映业务真实处理能力,QPS 反映底层接口的负载压力,两者结合才能定位到瓶颈在哪一段。
为了更直观,我列个对照表,把几个常被搞混的指标放在一起说明:
| 指标 | 含义 | 关注点 | 常见误用 |
|---|---|---|---|
| QPS | 每秒查询数(请求数) | 接口层面的吞吐 | 把失败请求也算成有效吞吐 |
| TPS | 每秒事务数 | 业务动作层面的吞吐 | 单接口压测时和 QPS 混着说 |
| 并发数 | 同时发起的请求数量 | 系统并行处理压力 | 把并发等同于线程数或用户数 |
| 响应时间 | 单请求从发出到返回的耗时 | 用户体验 | 只看平均值,不看 P95、P99 |
| 错误率 | 失败请求占比 | 系统可靠性 | 压测时不设阈值,只管冲高峰值 |
1.3 为什么 QPS 这个指标最容易被看走眼
说句实在话,QPS 是性能指标里最容易“造”出来的。我见过一些团队,为了让报告好看,只压一个最简单的查询接口,缓存全开,然后把几十万的 QPS 写进文档。这种数字对实际系统没有任何指导意义,因为真实流量是混合的,有读有写,有缓存命中也有击穿,有同步调用也有异步回调。
第二个容易看走眼的地方是平均值。平均响应时间 80 毫秒听起来很美,但如果 P99 是 3 秒,意味着每 100 个用户里就有 1 个要等三秒,这在真实的用户感知里就是“偶尔卡顿”。压测的时候一定要让工具把分位数打出来,Locust 会给你 50%、66%、75%、80%、90%、95%、98%、99% 这几个档位的响应时间,看 P95 和 P99 比看平均值有价值得多。
第三是“稳定”的假象。有些接口压 1 分钟很稳,压 10 分钟就开始内存上涨、连接数堆积,最后崩掉。这是资源泄漏的典型表现。所以我现在做压测,短则 10 分钟,长则跑几个小时,专门观察 QPS 曲线是不是一条横线,有没有缓慢下滑的趋势。只看 1 分钟的峰值,很容易漏掉这类问题。
2. 压力测试方案该怎么设计才不白测
2.1 先明确目标:你到底要回答什么问题
压测不是“跑个工具看数字”,它是要回答具体问题的。动手之前,我会先跟业务和研发把目标对齐,通常归成四类。第一类是容量摸底:这套系统在现有配置下,最多能扛多少 QPS,超过多少会出问题。第二类是回归验证:做了性能优化之后,新版本比老版本快了多少。第三类是瓶颈定位:知道系统扛不住,但不知道卡在哪,用压测去把瓶颈逼出来。第四类是稳定性验证:系统能不能在某个压力水平下连续跑几个小时不出错。
目标不一样,做法完全不一样。容量摸底要阶梯式加压,一级一级往上顶,直到找到拐点;回归验证要固定压力、固定时长,保证两次测试条件一致,唯一变量是代码版本;瓶颈定位要配合监控,把 CPU、内存、磁盘 IO、数据库指标全打开,边压边看;稳定性验证则要拉长时长,重点看错误率和资源曲线。我见过太多人上来就闷头压,压完一肚子数字不知道说明什么,就是因为一开始没想清楚要回答什么。
另外一定要提前确定验收标准。比如“接口 P95 响应时间不超过 200 毫秒、错误率低于 0.1%、QPS 不低于 5000”,把这些写进测试计划里。有了这条线,测完当场就能判断过没过,而不是靠感觉。没有验收标准的压测,最后往往变成一场“数字比大小”的表演。
2.2 压测模型:流量怎么造才像真实用户
这是整个方案里技术含量最高、也最容易被敷衍的一环。压测模型说白了就是“我们要模拟什么样的用户行为”。一个真实的用户不会是每秒发一次请求的机器人,他会有思考时间、会来回跳转、会集中访问某些热点数据、会有登录态和前置操作。如果你压测脚本就是无脑对同一个接口死循环,那测出来的数据参考价值非常有限。
我会从几个维度去还原真实流量。一是请求比例,比如订单系统里查单、下单、取消的比例大概是 10:3:1,那脚本里就用 Locust 的权重参数把这个比例配出来。二是参数分布,不能所有请求都查同一个用户 ID,要准备真实的参数池,用 CSV 或数据库捞一批,随机取用。三是思考时间,Locust 支持在请求之间加随机的等待间隔,模拟用户的停顿。四是前置状态,比如很多接口需要登录 token,得在脚本初始化时先登录拿到凭证。
这里有个特别容易踩的坑:如果所有虚拟用户都用同一个账号、同一个商品 ID,压测时数据全落在同一行记录、同一个缓存 key 上,测出来的性能会虚高。真实环境里数据是分散的,锁竞争、缓存分布、索引命中的情况完全不同。我一般会准备几百到几千条参数,让每个虚拟用户随机取,尽量贴近真实分布。这一步做扎实了,后面的结论才站得住。
2.3 环境、数据、监控三件套的准备
环境这块,我的原则是“尽可能贴近生产,但绝不在生产上乱来”。理想状态下压测环境要和生产的机器规格、网络拓扑、中间件配置保持一致,但现实中很难完全做到,那就退一步,把关键差异记录下来,在解读数据时心里有数。比如压测环境数据库是单机,生产是主从集群,那压出来的 QPS 只能作为下限参考,不能直接当成生产容量。
数据量级是另一个隐蔽的坑。一个表在有 100 万行数据时和有 100 行数据时,查询性能天差地别。压测前一定要把测试库的数据量灌到和生产同一个量级,尤其是那些会走索引、会做分页、会做聚合统计的接口。我见过压测时 QPS 很漂亮,上线后慢查询一堆的情况,十有八九就是测试库数据太少,索引全在内存里,什么查询都快。
监控必须提前部署好,而不是压到一半才想起来看。至少要有这几样:被测服务的 CPU、内存、GC 情况;数据库的连接数、慢查询、QPS;中间件的队列长度、堆积情况;压测机自身的负载。这里特别提醒一句,压测机自己也可能成为瓶颈,如果压测机的 CPU 跑满了、网络带宽打满了,那你测出来的不是被测系统的上限,而是压测机的上限。Locust 分布式压测就是为了解决这个问题,后面会详细讲怎么搭。
3. 工具选型:为什么我最后常驻 Locust
3.1 主流压测工具横向对比
市面上的压测工具挺多,我这些年用下来比较有代表性的有这几个:JMeter、Locust、wrk、ab,加上云厂商提供的托管压测服务。每个都有它的适用场景,没有绝对的好坏,关键看你的需求和团队情况。
| 工具 | 脚本方式 | 协议扩展 | 分布式 | 上手难度 | 适合场景 |
|---|---|---|---|---|---|
| JMeter | GUI + XML 配置 | 插件丰富 | 原生支持 | 中等 | 复杂业务流程、需要图形化编排 |
| Locust | 纯 Python 代码 | 写代码扩展 | 原生支持 | 中低(会 Python 即可) | 接口压测、需要灵活逻辑 |
| wrk | 命令行 + Lua | 需写 Lua | 不原生 | 较高 | 单接口极限压测,追求高并发 |
| ab | 命令行 | 几乎不支持 | 不支持 | 低 | 快速验证单个接口 |
| 托管压测服务 | 平台配置 | 视平台而定 | 平台负责 | 低 | 临时大流量压测、不想维护机器 |
JMeter 的教程网上一抓一大把,它对不写代码的同学很友好,图形界面点一点就能搭出流程。缺点是脚本是 XML,团队协作和版本管理比较别扭,复杂逻辑要靠各种组件堆,久了容易变成一坨“意大利面”。wrk 和 ab 适合单接口的快速极限压测,但业务逻辑一复杂就力不从心——比如要先登录、要参数化、要按比例混合多个请求,它们就不好使了。
Locust 打动我的地方在于它是“代码即脚本”。你用一个 Python 类描述用户行为,用装饰器标注任务和权重,整个逻辑清晰、可读、可复用、可进 Git。对于已经有 Python 基础的团队,学习成本非常低,而且你想加什么逻辑就加什么逻辑——随机参数、条件分支、自定义断言、串联多个接口,全都能写。这种灵活性是图形化工具比不了的。
3.2 Locust 的架构优势在哪
Locust 的架构有个很聪明的设计:它是基于事件驱动的,用的是 gevent 这类协程库。这意味着单个进程里可以用很少的系统开销模拟出大量并发用户。传统的一个线程模拟一个用户,几千并发就要几千个线程,上下文切换的代价非常大;Locust 用协程把这个问题绕开了,一台普通机器单进程跑几千并发不是难事。
它的另一个优势是分布式扩展特别顺。主节点(master)负责分发任务和汇总统计,工作节点(worker)负责实际施压,加机器就是线性加压力。你只要在被压的机器上多起几个 worker,或者在压测机上用多进程模式把多核吃满,压力就能成倍往上走。这套分发机制配置起来就几个命令行参数的事,比很多工具都省心。
还有一点是实时 Web UI。Locust 默认起一个网页界面,压测过程中你能实时看到 QPS 曲线、响应时间分布、失败请求列表,还能动态调整并发用户数,比赛式地往上加,边加边观察拐点在哪。对于做容量摸底这种需要“慢慢顶上去”的场景,这个交互体验非常好。当然,正式回归测试时我会关掉 Web UI,用无头模式(--headless)跑,方便集成到自动化流程里。
3.3 哪些场景 Locust 并不适合
得客观说,Locust 不是万能的。第一,它天生偏重 HTTP/HTTPS 这类协议,虽然有扩展机制可以支持别的协议,但你要压 gRPC、WebSocket 或者自定义的二进制协议,就得自己写客户端封装,工作量不小,这种时候专业的协议压测工具更合适。
第二,Locust 的绝对性能上限不如 wrk 这种 C 语言写的工具。它的优势是灵活和易用,追求极致单机吞吐的场景,wrk 更有竞争力。不过实际压测里,我们更多是分布式压,单机的那点差距可以通过加 worker 补回来。
第三,如果团队里完全没有 Python 基础,且只是做很标准的单接口压测,那用图形化工具或者托管服务可能更快出结果。工具是为目标服务的,没必要为了“显得专业”去选一个自己不熟的东西。我的建议是:需要复杂业务逻辑、需要灵活参数化、团队有 Python 底子的,选 Locust;纯粹压一个接口看极限的,wrk 或 ab 更省事。
4. Locust 实操:从零把一个接口压起来
4.1 环境搭建与安装
Locust 是 Python 写的,所以第一步是把 Python 环境准备好。我用的是 Python 3.8 以上的版本,装起来就一条命令:
pip install locust装完之后验证一下:
locust --version能打印出版本号就说明 OK 了。这里提醒一句,最好用虚拟环境隔离,避免和系统里其他库冲突:
python -m venv locust-env source locust-env/bin/activate pip install locustWindows 下激活命令是locust-env\Scripts\activate,其他步骤一样。装好之后不用急着写脚本,Locust 自带一个官方示例,可以直接拿来跑通,感受一下它的工作方式。
4.2 第一个压测脚本长什么样
Locust 的核心就是定义一个继承自HttpUser的类,类里的方法用@task装饰器标注,方法体里写你要发的请求。下面是我常用的一个模板,包含了登录拿 token、按权重混合多个请求、加思考时间这几个关键要素:
from locust import HttpUser, task, between class OrderUser(HttpUser): # 每个虚拟用户两次请求之间随机等待 1 到 3 秒 wait_time = between(1, 3) def on_start(self): # 每个虚拟用户启动时先登录,拿到 token resp = self.client.post( "/api/login", json={"username": "test_user", "password": "test_pass"}, ) self.token = resp.json().get("token", "") @task(3) def query_order(self): # 权重 3,查单逻辑占大头 self.client.get( "/api/order/list", headers={"Authorization": self.token}, name="订单列表", ) @task(1) def create_order(self): # 权重 1,下单逻辑 self.client.post( "/api/order/create", headers={"Authorization": self.token}, json={"skuId": 10001, "count": 1}, name="创建订单", )几个点解释一下。wait_time控制思考时间,不加的话虚拟用户会疯狂空转,压力会失真。on_start会在每个虚拟用户启动时执行一次,适合做登录这类前置操作。@task(3)里的数字是权重,表示这个任务被选中的相对概率,上面例子中查单和下单的调用比例大概是 3:1。每个请求都加了name参数,这是为了在报表里把同类请求聚合展示,否则带不同参数的 URL 会被拆成很多行,看报表很乱。
4.3 参数化:别让所有请求打在同一条数据上
前面说过,参数化是压测质量的关键。Locust 里最常用的做法是读 CSV,然后随机取行。示例:
import csv import random from locust import HttpUser, task, between class ParamUser(HttpUser): wait_time = between(0.5, 2) def on_start(self): # 从文件里加载参数池 with open("params.csv", newline="", encoding="utf-8") as f: self.params = list(csv.DictReader(f)) @task def query_detail(self): p = random.choice(self.params) self.client.get( f"/api/product/{p['sku_id']}", name="商品详情", )params.csv里就放真实的sku_id、用户 ID 这类字段,几百上千条起步。这样每个虚拟用户取到的参数都不一样,能更真实地模拟数据分散访问的情况。如果参数池太小,比如只有十条,那本质上还是在压同几条记录,测出来的数据会偏乐观。参数池的大小,我的经验是至少覆盖你能想到的热点数据边界,有条件的话直接从一个脱敏的生产数据副本里捞。
4.4 分布式压测怎么把压力顶上去
单机压不动的时候,就该上分布式了。Locust 的分布式很直白:一台机起 master,其余机起 worker,worker 连上 master 后由 master 统一发号施令。
先在一台机器上启动主节点:
locust -f locustfile.py --master --web-port 8089然后在其他机器上启动工作节点,指向主节点的地址:
locust -f locustfile.py --worker --master-host=192.168.1.100启动成功后,在 master 的 Web UI 里设置并发用户数,任务会自动分摊到各个 worker 上,统计结果也由 master 汇总。加 worker 的过程可以随时进行,压力不够就多挂几台。
这里有个很多新手不知道的甜点:如果压测机是多核的,其实不用多台机器,单机上也可以把多个核吃满。用--processes参数指定进程数即可:
locust -f locustfile.py --headless -u 2000 -r 100 --processes 8-u 2000是目标并发用户数,-r 100是每秒启动多少用户(爬坡速率),--processes 8表示起 8 个进程并行施压,一般设置成 CPU 核数或多一点。这种方式省去搭多机的麻烦,性价比很高,我在压测机有 8 核以上的时候基本都用它。前提是压测机本身别成为瓶颈,压的时候盯一下它的 CPU 和网络。
4.5 Web UI 和无头模式的用法与选择
Web UI 模式适合探索性压测。访问http://压测机IP:8089,填上并发数和爬坡速率就能开跑。界面上几块核心信息要会看:Statistics 里是各接口的请求数、失败数、响应时间分位数和 RPS;Charts 里是实时曲线;Failures 里能看到失败请求的具体报错。我一般会用它做“阶梯加压”——先设 100 并发跑两分钟看曲线,没问题就加到 200、500、1000,一级一级观察 QPS 和响应时间的变化,拐点往往就在某次加压后突然出现。
正式测试或者要集成到 CI 里时,我会用无头模式:
locust -f locustfile.py --headless -u 500 -r 50 -t 10m --csv=result --html=report.html-t 10m表示跑 10 分钟,--csv导出原始数据,--html生成一份可直接发给同事的报告。这套命令适合放进自动化脚本里定时跑,做版本间的性能回归对比。结果解读的时候,重点盯三样东西:成功请求的 RPS、P95/P99 响应时间、错误率。这三个指标任何一个掉链子,都说明这次压测发现了问题。
5. 常见问题与排查技巧实录
5.1 压力死活压不上去的几种典型原因
压测时最常见的困惑就是:并发数加了,QPS 却一动不动。这时候别急着怀疑被测系统,先按顺序排查。第一件事是看压测机自身的负载。用top看一下 CPU 使用率,sar -n DEV 1看一下网卡流量。如果压测机 CPU 已经跑满或者网卡已经打满,那你测的是压测机的上限,不是系统的上限。解决办法是加 worker 或者加机器,把压力分散开。
第二件事是检查客户端的连接数限制。Linux 默认单进程能打开的文件描述符有限,高并发时会出现“Too many open files”的报错。临时调高的话:
ulimit -n 65535永久生效要改/etc/security/limits.conf。这个坑我踩过好几次,压到几千并发就莫名其妙报错,查半天才发现是文件描述符到了上限。
第三件事是端口耗尽。客户端每次发请求都要占一个本地端口,端口范围是有限的,短连接压测时端口回收不过来,就会连接失败。可以调大本地端口范围,或者改用长连接。Locust 的HttpUser默认会复用连接,如果你用的是自定义客户端,注意别每次请求都新建连接。
5.2 结果数据自相矛盾的排查思路
还有一种情况是数据看着不对劲。比如 QPS 显示很高,但后端监控里数据库的请求量根本对不上。这时候先看是不是压测机到服务端之间走了缓存或者 CDN,请求根本没打到后端。再比如平均响应时间很短,但 P99 特别长,说明有少量请求卡住了,可能是偶发的锁等待、GC 停顿或者慢查询,要结合后端日志去挖。
失败率高但报错信息含糊的,我一般先用小并发复现。50 并发跑一遍,如果也报错,观察具体的前几个失败请求的完整响应体,往往能直接找到原因,比如 401 未授权(token 逻辑有问题)、429 限流(触发了网关限流)、500(后端异常)。Locust 的 Failures 页面会分组展示失败原因,善用这个功能能省很多事。另外记得区分“服务端错误”和“压测端主动超时”,前者是真问题,后者可能是你设置的超时时间太短,把正常但稍慢的响应也算成失败了。
5.3 常见问题速查表
把压测过程中高频出现的问题和应对方式整理成一张表,方便现场对照:
| 现象 | 可能原因 | 排查手段 | 处理方式 |
|---|---|---|---|
| QPS 上不去,压测机负载高 | 压测机成为瓶颈 | 看压测机 CPU、网卡 | 加 worker、加机器、调--processes |
| 报 Too many open files | 文件描述符不足 | 查ulimit -n | 调高系统限制 |
| 大量连接失败 | 本地端口耗尽 | 查连接状态统计 | 调大端口范围、改用长连接 |
| 失败率高,含 429 | 触发限流 | 看响应体和网关日志 | 调整压测速率或申请放开限流 |
| 平均响应快但 P99 高 | 偶发慢请求 | 看后端慢查询、GC 日志 | 定位个例,优化慢路径 |
| 跑久了 QPS 缓慢下滑 | 资源泄漏或连接堆积 | 观察内存、连接数曲线 | 排查泄漏点,检查连接回收 |
| 数据库请求量对不上 | 走了缓存或中间层 | 看缓存命中、网关转发 | 确认请求真实到达后端 |
注意:压测前一定和生产、运维确认好限流、熔断、告警策略。很多系统对异常流量有自动防护,压测很容易触发,导致结果失真甚至影响线上,务必提前打个招呼把相关策略临时调整或加白名单。
6. 换个视角:模型调用与各类资源压测
6.1 模型调用场景下 QPS 有什么不一样
现在越来越多系统后面接的是模型服务,这时候 QPS 的含义和传统接口就有些区别了。传统接口的 QPS 和响应时间关系比较线性,你加并发,响应时间缓慢上升,到瓶颈才陡增。而模型推理服务的响应时间往往很长(几百毫秒到几秒不等),而且波动大,受输入长度、生成长度、批次调度策略影响明显。这时候谈 QPS 就必须带上“在什么输入长度、什么输出长度下”的前提,否则数字毫无可比性。
模型服务的 QPS 优化思路也和普通接口不同。普通接口靠加缓存、优化 SQL 能立竿见影,模型服务更多是走批处理、动态 batching、算子优化、量化加速这些路子。压测这类服务时,我特别关注两个额外指标:单请求的排队等待时间,以及不同并发下吞吐量的变化曲线。很多时候并发加到某个点后,吞吐不再上升,延迟却急剧增加,这说明推理资源已经饱和,再堆并发只会让所有请求一起变慢,用户体验反而更差。
还有一点,模型服务的压测请求内容本身要贴近真实。输入是一句话还是几千字,结果差别巨大。如果压测只发很短的空输入,测出来的 QPS 会好看得离谱,完全没有参考价值。所以压测数据要么从真实请求采样,要么根据业务场景构造出合理的长度分布。
6.2 接口压测、CPU、GPU、存储压测的区别
需要说明的是,日常说的“压力测试”覆盖面很广,接口和模型服务压测只是其中一类。系统层面的压力测试还包括对 CPU、GPU、存储等硬件资源的专项压测,目的各不相同,别混为一谈。
CPU 压测主要是为验证散热和调度能力。常见的做法是用stress-ng或专门的烤机工具,把指定核心的负载打满,观察温度、频率是否稳定、有没有降频。这类测试在装机、服务器上架前做得多。GPU 压测也是类似思路,用专门的 GPU 负载工具让显卡持续高负载运行,检查散热和显存是否有异常,常用于新卡上机或者驱动验证。这些属于硬件层面的可靠性验证,和接口 QPS 不是一回事,但都会影响服务最终能承受的压力。
存储压测关注的是磁盘的读写能力。比较常用的方法是用dd或者更专业的文件系统压测工具,对某个目录持续写入和读取,测量顺序读写、随机读写的带宽和 IOPS。比如对应用的数据盘做一次写测试,看写入速度是否符合预期,是否存在掉速。这和接口压测的关系在于:如果你的接口涉及大量文件读写或者日志落盘,磁盘的 IO 能力很可能是隐藏瓶颈,接口压测时 QPS 上不去,最后追查发现是磁盘 IO 打满了。所以完整的压测方案,往往需要接口层和资源层结合着看,才能定位到真正的问题所在。
我自己的习惯是,接口压测的同时把所有资源指标都挂在监控大屏上,哪个资源先顶到天花板,瓶颈就在哪。CPU 先满,说明计算密集;内存先满,可能有泄漏或者缓存过大;磁盘 IO 先满,检查日志和文件操作;网络先满,考虑是不是响应体太大。把这几个维度和接口 QPS 放在一起看,排查效率会高很多。压力测试从来不是跑一个工具就完事,它是一套结合了目标设定、模型设计、资源观测和结果分析的完整方法,Locust 只是这套方法里顺手的一把趁手工具。
最后再分享一个我自己的小习惯:每次压测结束,不管结论好坏,我都会把脚本、参数文件、环境说明和结果报告一起归档到一个目录里,命名带上日期和版本号。过段时间要做性能回归,直接翻出来照着跑,条件一致,对比才有意义。踩过的坑大多记在这些报告里,下次遇到类似的现象,翻一翻往往就能少走弯路。