96SEO 2026-04-24 13:42 19
Zui近手头有个小项目眼kan就要上线了心里总是七上八下的。虽说代码逻辑自测了几遍,但真要放到公网上,面对未知的流量洪峰,它到底Neng扛住多少并发?这个问题一直像个幽灵一样盘旋在脑海里。之前听圈里的朋友反复提起过 Locust,据说这玩意儿是用 Python 写脚本来Zuo压测,比那些笨重的 GUI 工具轻量多了。正好趁着这个周末,我决定彻底摸一摸它的底,顺便把这几天的踩坑经历和心得整理下来给同样想入门的朋友Zuo个参考。

说实话,市面上的性Neng测试工具真不少,老牌的 JMeter、k6,还有那种极简的 wrk,我dou略有耳闻。但为什么Zui后锁定了 Locust?理由其实特别简单粗暴:它用的是 Python。
对于咱们这种平时写业务代码的开发者来说为了写个压测脚本去专门学一门新语言或者在一堆复杂的 GUI 菜单里点来点去,实在是一件痛苦的事。而且 GUI 工具Zui大的坑在于版本控制——你hen难直观地kan出两次测试之间脚本改了哪儿。Locust 就不一样了它的脚本本质上就是一个普通的 Python 文件。你想怎么写就怎么写,条件判断、循环、读文件、调第三方库,全dou是你熟悉的语法。这种“测试即代码”的感觉,真的太顺滑了。
环境搭建:从零开始的准备工欲善其事,必先利其器。现在的 Python 包管理工具越来越卷,我Zui近迷上了 uv,速度简直飞起。当然Ru果你还是习惯传统的 pip,那也完全没问题,殊途同归嘛。
我们得把项目目录建起来然后把 Locust 请进门。Ru果你也用 uv,流程大概是这样的:
# 先建个文件夹
mkdir locust-practice && cd locust-practice
# 初始化项目
uv init
# 把 Locust 加到依赖列表里
uv add locust
这几条命令敲下去,环境就基本搞定了。它会自动处理虚拟环境和 Python 版本的问题,省去了以前手动 venv 那一套繁琐的操作。Ru果你是 pip 的忠实拥趸,等价命令就是下面这样,效果是一样的:
python -m venv .venv
source .venv/bin/activate # Windows 用户记得换成 .venv\Scripts\activate
pip install locust
装好之后别急着写代码,先确认一下版本号,确保一切正常:
uv run locust -V
# 或者Ru果你用的 pip:
locust -V
只要终端乖乖吐出了版本号,那就说明咱们Ke以开工了。
第一个脚本:五分钟上手在项目根目录下新建一个 locustfile.py。这是 Locust 默认识别的文件名,当然你非要叫别的名字也行,到时候启动时指定一下就是了。
咱们先写个Zui简单的“Hello World”级别的脚本,感受一下它的画风:
from locust import HttpUser, task, between
class WebSurferUser:
# 模拟用户在两个请求之间的等待时间,这里是 1 到 3 秒之间
wait_time = between
@task
def visit_homepage:
self.client.get
@task
def visit_headers:
# 权重设为 3,意味着这个接口被访问的概率是普通 task 的 3 倍
self.client.get
你kan,就这么几行代码,其实Yi经是一个具备完整功Neng的压测脚本了。这里有个值得停下来细品的设计理念:我们并没有写任何显式的“压测逻辑”。我们只是描述了一个用户会Zuo什么动作——访问首页,或者kankan Headers。至于怎么控制并发、怎么统计数据、怎么画图表,那全是 Locust 框架替我们在后台默默搞定的事。这就是它所谓的“测试即代码”的精髓。
脚本写好了怎么跑呢?打开终端,输入:
uv run locust -f locustfile.py
这时候终端会提示你 Web 界面Yi经启动了通常是在 http://0.0.0.0:8089。咱们用浏览器打开这个地址,就Nengkan到 Locust 的控制台了。界面上有三个框要填:
Number of users: 你想模拟多少个虚拟用户?
Spawn rate: 每秒钟启动多少个用户?
Host: 你要压测的目标网站地址。
填好这些参数,点击那个诱人的“Start swarming”按钮,压测就开始了。几秒钟后切到 Statistics 页面你就Nengkan到每个接口的实时数据:请求数、失败数、中位响应时间、RPS 等等。再切到 Charts 页,还Nengkan到漂亮的曲线图。想停的时候,点一下 Stop 就行,是不是比想象中简单多了?
避坑指南:关于 QPS 和 并发数的误区刚开始玩 Locust 的时候,我犯了一个特别经典的错误:以为“100 个虚拟用户”就等于“100 QPS”。后来被现实狠狠打脸,才反应过来这俩完全是两码事。
这里的关键在于 wait_time。一个虚拟用户在 Locust 里的生命周期是这样的:执行一个 task -> 等待 wait_time -> 再执行下一个 task。
Ru果你的 wait_time 设置成了 between,平均下来就是 2 秒。那么一个用户平均每 2 秒才发一个请求,也就是 0.5 QPS。这种情况下100 个用户撑死也就只Neng产生 50 QPS。所以想压到 100 QPS,你得反推一下:目标 QPS × 平均 wait_time = 需要的用户数。在这个例子里就是 100 × 2 = 200 个用户。
还有个极端的坑,就是把 wait_time 设成 0。一开始我觉得这样Neng压出Zui大压力,简直是“核弹级”选项。但后来想明白,这其实是个伪命题,甚至是个危险的陷阱。
为什么?因为真实用户绝对不会 0 间隔地连续狂点鼠标。Ru果你用 0 等待去压测,得到的是一个“机器人式的极端场景”,根本反映不出正常业务下的服务表现。geng糟糕的是Ru果你的服务里有连接池、限流、缓存预热这些机制,0 等待的压测会让这些机制的表现完全偏离实际线上情况。测出来的数据,要么是把自己吓死,要么是盲目乐观。
我现在比较推荐的Zuo法是:去翻一下线上的访问日志,kankan真实用户的点击间隔大概是多少,然后用 between 设一个接近的范围。Ru果实在没数据,1 到 5 秒是个比较保守且合理的默认值。
光会访问静态页面肯定不够,咱们得来点真格的。真实业务往往复杂得多,下面这几个场景是我摸索过程中觉得Zui实用的。
1. 处理用户登录大部分业务接口dou要登录鉴权才Neng访问。Locust 提供了一个特别贴心的钩子 on_start。每个虚拟用户“出生”的时候,dou会执行一次这个方法,简直就是为登录逻辑量身定Zuo的。
from locust import HttpUser, task, between
class LoggedInUser:
wait_time = between
def on_start:
# 每个虚拟用户启动时先去登录一次
response = self.client.post("/api/auth/login", json={
"username": "testuser",
"password": "mypassword"
})
# 拿到 token 后把它塞到后续请求的 header 里
token = response.json.get
self.client.headers.update({
"Authorization": f"Bearer {token}"
})
@task
def view_my_profile:
self.client.get
这里有个细节特别棒:self.client 是每个用户独立的。你在 on_start 里设置的 header,只会作用于这个用户后续的请求,完全不会污染其他用户。这种隔离性设计,真的省了不少心。
当然Ru果你的 token 有过期时间,逻辑稍微复杂点。你Ke以再加一个 on_stop Zuo登出清理,或者在 task 里检测到 401 之后重新登录。反正这就是普通的 Python 代码,你想怎么写逻辑dou行,Locust 不会限制你。
真实用户的行为从来dou不是均匀分布的。拿电商网站来说大部分时间大家dou在浏览商品,少部分人会加购物车,只有极小一部分人会真的下单。Ru果你的压测脚本里浏览、加购、下单的比例是 1:1:1,那测出来的结果肯定严重偏离现实。
这时候就要用到权重了。给 @task 装饰器传个数字进去就行:
class ShopperUser:
wait_time = between
@task # 浏览商品权重高
def browse_items:
self.client.get
@task # 下单权重低
def place_order:
self.client.post
这里的比例就是 3:1。Locust 会按照这个概率分布随机挑选任务执行。建议你在设权重的时候,Zui好去查一下自己服务的真实访问日志,照着线上的实际比例来设。hen多人容易凭感觉拍脑袋,但感觉和现实往往差好几倍——这种压测结果不仅没用,反而是误导性的。
3. 数据参数化hen多场景下每个虚拟用户应该用不同的数据。比如压测登录接口,Ru果 1000 个用户dou用同一个账号“testuser”去登录,后端可Neng直接走了缓存,或者被限流策略拦截,压出来的数据完全不准。
Zui简单的Zuo法是用个 CSV 文件存一批测试账号,然后在脚本里读。这里有个小技巧:CSV 文件的读取Zui好写在类外面这样只会读一次所有用户共享这份数据。Ru果你手滑把它写到 on_start 里那每个用户启动时dou要去读一次文件,要是启动几千个用户,磁盘 IO Neng把你卡死。
import csv
import random
from locust import HttpUser, task, between
# 在文件顶部加载一次所有用户共享
with open as f:
TEST_ACCOUNTS = list)
class VariableUser:
wait_time = between
def on_start:
# 每个虚拟用户启动时随机挑一个账号
creds = random.choice
self.client.post
@task
def do_something:
self.client.get
Ru果你需要geng高级的“每个用户用一个独立账号且不重复”,Ke以用 itertools.cycle 配合一个带锁的迭代器。虽然稍微复杂点,但也还是那句话——这就是 Python,随你怎么写。
默认情况下Locust hen单纯:HTTP 状态码 2xx 算成功,4xx/5xx 算失败。但现实是残酷的,hen多接口就算返回了 200,业务层面也可Neng是失败的。
比如这种场景:
{
"code": 400,
"message": "余额不足"
}
HTTP 状态码是 200,但业务逻辑告诉你这单子没成。这时候就需要自定义判断逻辑了。self.client 提供了一个上下文管理器模式,专门干这个:
class SmartUser:
wait_time = between
@task
def buy_item:
with self.client.post as response:
if response.status_code != 200:
response.failure
elif response.json.get != 0:
# 这里捕捉到了业务层面的失败
response.failure.get}")
else:
response.success
关键是那个 catch_response=True 参数。加上它之后你就掌握了主动权,Ke以手动调 response.success 或 response.failure。写了自定义断言之后Locust 的 Failures 页面就Neng清晰地kan到具体的业务错误原因,排查起来简直不要太爽。
Locust 的 Statistics 页面默认显示的是“平均响应时间”。但我必须严肃地提醒你:在性Neng测试里平均值是一个非常有误导性的指标。
举个极端的例子:你有 100 个请求,99 个dou在 50ms 内返回,只有 1 个卡了 5 秒钟。算下来的平均值大概是 100ms。乍一kan,“哇,平均响应时间才 100ms,性Neng不错嘛!”
但实际上,那 1% 的用户经历了 5 秒的卡顿,这在生产环境绝对是严重的灾难,用户早就把网页关了。所以一定要养成盯着 P95 和 P99 这两个数据kan的好习惯。
简单解释一下:P95 意味着 95% 的请求比这个时间快,P99 意味着 99% 的请求比这个时间快。这两个指标才真正反映了“Zui差情况下的用户体验”。Locust 的 Statistics 页面有这两列,不过位置稍微有点偏右,一开始容易忽略,记得往右拉拉滚动条kankan。
当单机扛不住时:分布式压测单台机器Neng压出多大 QPS?这个问题没有标准答案,全kan你的脚本复杂度、网络带宽和 CPU 性Neng。但有几个明显的信号Ke以判断单机Yi经到瓶颈了:
压测机自己的 CPU 占用率接近 100%;
网络带宽跑满了;
Locust 报错说丢包或者连接超时。
Ru果出现这些情况,你测出来的数据就不可信了——不是目标服务扛不住是打枪的人先累趴下了。这时候,就该上分布式了。Locust 的分布式架构设计得非常清爽:一个 Master 负责调度和收集数据,多个 Worker 负责真正发请求。
怎么搞呢?先在一台机器上启动 Master:
uv run locust -f locustfile.py --master
然后在另外几台机器启动 Worker:
uv run locust -f locustfile.py --worker --master-host=
启动好之后Master 的 Web UI 用起来跟单机一模一样,Locust 会自动把用户均匀分配给各个 Worker。你只管点 Start,剩下的脏活累活框架dou帮你分摊了。
我的经验是:Ru果你要压的 QPS 超过 1000,或者脚本里有特别复杂的业务逻辑导致单机用户数撑不到几百,就Ke以考虑分布式了。平时压个几百 QPS 的接口,单机完全足够,没必要把事情搞得太复杂。
与心得花了大半天时间摸索下来我对 Locust 的总体感受是:这是一个“门槛低、天花板不低”的神器。
简单场景,比如压压静态页面五分钟上手,跑得飞快。遇到复杂需求,比如要处理复杂的鉴权链路、要根据上一步的响应动态构造下一个请求、或者要搞分布式集群,靠普通的 Python 代码也基本douNeng搞定。对于咱们这种不是专职Zuo性Neng测试、只是偶尔想压一下自己服务的开发者来说它够用,而且用着顺手。
Zui后再啰嗦一句我的私房心得:压测的意义从来不在于“跑出一个漂亮的 QPS 数字”去发朋友圈炫耀,而在于提前发现你的服务在什么地方会先挂。数字本身没那么重要,它挂的方式——是数据库连接池爆了?是缓存击穿了?还是 CPU 算满了?——这才是你真正要了解的东西。
Ru果你也想试试,我的建议是别一上来就去啃那厚厚的官方文档。就从本文这个几十行的 locustfile.py 开始跑,跑通了再按自己业务的需要一点点往上加功Neng。这个工具的学习曲线基本是线性的,不会突然陡峭,不用太担心。文章里的代码dou是我自己跑通过的,Ke以直接复制运行。Ru果有写错的地方,欢迎在评论区指正——毕竟我自己也才学了没多久,咱们一起进步。
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback