ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Locust压测实战指南:从脚本编写到分布式压测的完整攻略

Locust压测实战指南:从脚本编写到分布式压测的完整攻略 1. 为什么最后选了Locust压测工具对比后的真实结论先说个背景。去年底我们给一个支付回调接口做容量评估线上峰值QPS预估在3000左右压测目标是把服务打到极限看看它在什么时候开始报错、数据库连接池什么时候被拖垮。一开始团队里有人提议直接用JMeter理由是大家都会也有人建议上wrk说C写的性能好。但真的打开JMeter开始录制脚本时问题就来了回调接口的签名校验逻辑在代码里JMeter里想模拟一套完整的签名生成流程要么写BeanShell脚本要么自己写个JAR包塞进classpath折腾半天还没开始压。后来我提了个方案用Python Locust重写整套压测逻辑。理由很简单——接口的验签、加解密、请求头拼装这些逻辑本来就在Python服务端代码里直接复用一套签名工具函数在Locust脚本里调用就行不用做任何跨语言翻译。最终压测顺利跑完过程也比预想中干净得多。Locust这个框架核心就一句话用纯Python代码描述用户行为用协程gevent模拟海量并发。你不需要学一套XML配置语言不需要拖组件连线所有逻辑都写成普通Python方法想怎么玩就怎么玩。它的并发模型和JMeter的线程池模型有本质区别JMeter每个虚拟用户就是一个线程线程切换和内存开销都不小Locust的每个虚拟用户是一个协程一个进程可以轻松支撑几千个协程单机压测能力在绝大多数场景下是够用的。如果你也在选型我给一个直白的建议如果压测目标是HTTP API且你需要复杂的业务逻辑登录态、签名、数据关联无脑选Locust别犹豫。如果压测目标是数据库、文件系统这类底层协议或者需要依赖JMeter生态里现成的协议插件那JMeter更合适。如果只是想快速测一下Nginx的转发性能wrk就够了没必要上框架。这个判断逻辑是性能测试工具的本质是帮你把压力生成这件事抽象掉让你专注在业务场景上。业务越复杂、越贴近代码逻辑越该选代码型工具。2. 环境准备和安装版本选择、依赖坑和第一个启动2.1 Locust版本怎么选Python版本怎么配安装看上去简单pip install locust一行搞定但版本坑我觉得值得先说清楚。Locust从1.0版本开始API有重大调整早期的from locust import Locust继承类写法已经废弃了现在统一用HttpUser这个类。如果你在网上搜到旧教程代码里还在用class User(Locust)那是0.x时代的写法在2.x版本下直接跑不起来。我在生产环境压测用的Python版本是3.8到3.11都验过没有发现兼容性问题。比较稳妥的选择是Python 3.9或3.10这两个版本在绝大多数CI环境里都预装了不用额外折腾。Locust本体依赖的核心库是gevent、geventhttpclient、msgpack、psutil这几个pip会自动拉取正常情况下不会出幺蛾子。安装命令python -m venv locust_env source locust_env/bin/activate pip install locust locust --version这里有一个很多人忽略的细节建议用虚拟环境而不是直接装到系统Python里。原因有两个——一个是Locust的依赖版本迭代比较快直接装全局容易和系统里其他项目的flask、requests版本冲突另一个是压测机上我经常需要同时跑多个版本的Python项目虚拟环境隔离避免了互相污染。2.2 macOS和Windows上的两个新手劝退问题如果你在macOS尤其是M1/M2芯片上安装时看到gevent相关的编译报错比如error: command clang failed with exit status 1十有八九是因为Homebrew的Python环境缺少编译依赖。解决办法是在装Locust之前先装gevent的二进制wheelCFLAGS-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include pip install geventWindows上的问题不一样。很多人装好了Locust本地起一个压测脚本发现并发数到1000左右就上不去了各种ConnectionError满天飞。这个锅不全在LocustWindows默认的临时端口范围有限。用管理员权限执行下面两条命令扩一下范围再压netsh int ipv4 set dynamicport tcp start10000 num50000 netsh int ipv4 set dynamicport udp start10000 num50000而且Windows上的gevent对select模型的适配不如Linux我们后来规范化为本地开发用macOS或Windows做语法验证和单机小并发调试正式压测一律跑在Linux机器上。这不是偏见是实测数据说话。同样一个脚本Windows上跑800并发就开始报错同样的机器配置换Linux跑3000并发稳如老狗。2.3 最小可用示例先让压测跑起来环境装好后我习惯先用一个最小的脚本验证框架可用性再往里面填充业务逻辑。这个最小脚本长这样from locust import HttpUser, task, between class QuickUser(HttpUser): wait_time between(1, 3) task def hello(self): self.client.get(/health)用locust --host http://127.0.0.1:8080/启动之后浏览器打开http://localhost:8089填入用户数和 spawn 速率就能看到压测曲线了。别小看这个脚本里面每一个配置都有讲究wait_time控制的是每个虚拟用户在执行完一次task之后、开始下一次task之前的等待时间模拟的是真实用户的思考时间task标记了这是用户会执行的行为self.client是HttpUser内置的HTTP客户端它本质上是requests.Session会自动处理Cookie、连接复用。所以你在脚本里向服务端登录之后后续所有请求都会自动带着登录态这是Locust脚本比JMeter脚本好写很多的一个点。3. 写压测脚本的核心任务集、权重、等待时间和用户数据3.1 task和TaskSet的正确打开方式很多刚上手Locust的人会问一个问题一个压测场景里用户行为有登录、浏览、下单、支付怎么组织脚本结构答案是TaskSet类。TaskSet可以把一组相关任务绑定在一起并且支持任务间权重控制from locust import HttpUser, TaskSet, task, between class UserBehavior(TaskSet): def on_start(self): self.client.post(/login, json{username: demo, password: 123456}) task(5) def browse_product(self): self.client.get(/product/1001) task(1) def create_order(self): self.client.post(/order, json{product_id: 1001, quantity: 1}) task(1) def pay_order(self): self.client.post(/pay, json{order_id: self.order_id}) def on_stop(self): self.client.post(/logout) class WebsiteUser(HttpUser): tasks [UserBehavior] wait_time between(1, 5)解释几个关键点。task(5)里的数字是权重。上面这个例子里browse_product背负了5份权重create_order和pay_order各1份意味着在随机分配任务时浏览商品的概率是创建订单的5倍。这个权重值应该怎么定最理想的情况是从线上埋点数据里统计真实用户的行为比例。没有埋点数据的话就让业务方按经验给一个估算值总比所有任务等概率分布要贴近真实场景。on_start方法在每个虚拟用户启动时执行一次这个设计用来做登录、初始化、读取种子数据这类一次性操作。注意它是在协程里运行的所以在这里做的耗时操作比如远程读取一批测试账号会阻塞这个虚拟用户后续的任务调度。如果你压测场景需要大量用户每个人都去远程拉数据那压力生成阶段会非常慢数据接口本身反而成了瓶颈。3.2 wait_time四种策略怎么选等待时间的设置看似简单实则是压测结果可信度的关键。如果完全不等待每个虚拟用户会尽快循环执行任务这会造成一种比真实场景更猛烈的压力适合做极限打满测试但不适合做容量评估。constant(3)每个任务后固定等3秒适合模拟机械性操作比如机器人轮询接口。between(1, 5)每个任务后随机等待1到5秒模拟真实用户的行为波动。constant_pacing(5)保证每个任务从开始到下一次开始之间的时间跨度固定为5秒。如果你的目标是让每个用户每秒固定发出N个请求用这个。constant_throughput(2)这个策略最特殊它把用户吞吐量换算成等待时间目标是让每个用户的请求频率恒定在每秒2次。注意它里面的total_time是任务执行时间和等待时间之和所以在做慢接口压测时要小心如果接口响应时间本身超过了设定的吞吐间隔它会补偿等待时间为0。我实际用得最多的是between和constant_pacing。前者做容量评估后者做用户行为不可变、后端响应变慢的排队场景模拟。有一点必须提醒如果被压接口响应时间很长比如超过wait_time虚拟用户的任务循环会退化成等响应立马发下一个请求的模式这时候压力曲线就完全由响应耗时驱动了。这种情况要么是设计问题目标就是测长任务要么就是后端已经快挂了你要能分辨清楚。3.3 参数化和数据隔离别让所有用户都用一个账号压测里最怕的就是环境不支持高并发登录然后你的脚本又让每个虚拟用户复用同一个账号去登录结果压测还没开始登录接口先被打崩了。解决方案是创建用户数据文件每个虚拟用户使用自己独立的数据。我用得比较顺手的方式是从CSV里读取账号在on_start里按虚拟用户序号取一行。import random from locust import HttpUser, task, between class DataDrivenUser(HttpUser): wait_time between(1, 2) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.user_data None def on_start(self): with open(users.csv, r) as f: lines f.readlines() line random.choice(lines) username, password line.strip().split(,) resp self.client.post(/login, json{username: username, password: password}) if resp.status_code 200: self.token resp.json()[token] self.client.headers.update({Authorization: fBearer {self.token}})注意这里有一个容易被忽略的点on_start里的文件读取不能写成加载一堆数据到内存里分发给所有用户因为每个用户协程都是独立执行的你的一次open()只对当前用户生效。如果你有1000个虚拟用户这个文件会被打开1000次。真正生产级的做法是提前加载到内存然后用self.environment.runner.user_classes配合用户ID做索引或者用一个全局的itertools.cycle生成器让每个用户按顺序拿测试数据避免重复随机选择导致的碰撞。压测过程中如果客户端的token失效了还要在后续任务执行前主动做一次重新登录否则压测后期的请求全返回401统计结果没什么参考价值。3.4 失败处理和依赖任务的组织压测脚本里还有一个很容易被忽视的点失败任务的语义。默认情况下self.client.get()方法如果遇到网络错误或超时会抛异常Locust会记录失败次数。但如果接口返回4xx、5xx状态码requests库不会主动抛异常Locust也不认为这是失败只会记录状态码统计。如果你想把这些非200响应标记为失败需要显式判断with self.client.get(/order/list, catch_responseTrue) as resp: if resp.status_code 500: resp.failure(Server error) elif resp.status_code 200: if expected_data not in resp.text: resp.failure(Response content mismatch)这个catch_response上下文管理器是Locust里最实用的API之一它不会吞掉响应只是允许你自定义成败判定。在企业内部压测时比有没有报错更重要的是返回的响应内容是否符合预期——接口200了但返回的是一段错误兜底JSON这在压测报告里很难看必须靠脚本层面拦住。任务依赖又是一个比较细的点。比如下单任务依赖登录登录任务依赖注册。Locust里没有现成的前置任务机制但你可以用实例变量保存状态然后在每个任务开头判断前置条件是否满足不满足就直接跳过当前任务或者调用self.interrupt()跳出当前TaskSet。我用过的模式是登录请求放在on_start下单任务里如果发现token失效就重新登录再下单。这样的设计让任务之间保持低耦合后面接分布式压测时不容易踩坑。4. 跑起来Web模式、命令行参数和结果怎么读4.1 Web模式的操作节奏和技巧本地调试时我基本都用Web模式。启动命令locust --host https://api.example.com --web-host 0.0.0.0 --web-port 8089浏览器打开后界面会让填两个参数Number of users总用户数和Spawn rate每秒启动多少用户。我第一次用的时候也是草草填个100、10就开始压了但实际压测的节奏是有讲究的第一个阶段设置一个较小的并发比如50观察接口延迟确认脚本逻辑没问题、没有权限报错。第二个阶段逐步提高并发观察RPS和P95延迟的曲线变化找到拐点。第三个阶段保持高并发持续运行一段时间至少10分钟看是否有内存泄漏、连接池耗尽这类延迟出现的问题。Web模式的图表页签展示的是RPS、响应时间、用户数三个核心指标的时间曲线。Charts页里能直接看到直方图Request Stats表格里能看到每个接口的平均响应时间、中位数、90%分位、95%分位、99%分位和失败率。全绿不代表系统健康要重点看的是P95曲线有没有随用户数增加而急剧拉升。Web模式最大的坑是它本身也是占用资源的。压测时浏览器刷新图表会比较耗CPUWeb服务本身也跑在Locust进程里。所以大规模压测时比如分布式、几千并发我从来不在压测机上开Web界面全程用headless模式跑压完了再生成HTML报告。4.2 命令行模式CI里跑压测的正统姿势命令行模式更适合脚本化、自动化。直接给参数让Locust跑完自动退出locust --host http://target.example.com --headless -u 300 -r 20 --run-time 10m --csvresult --htmlreport.html这里-u 300表示模拟300个用户-r 20表示每秒启动20个用户--run-time 10m表示运行10分钟。如果只跑30秒就结束数据波动太大没有参考意义我一般根据接口实时性设定最短5分钟。--csvresult会生成三个文件result_stats.csv聚合统计每个接口一行包含请求数、平均响应时间、各分位数、RPS、失败率。result_stats_history.csv按秒采样的时间序列数据适合自己写脚本画图。result_failures.csv失败明细。--htmlreport.html生成的是离线HTML报告比Web界面上的数据更全含图表和分位数汇总。这个报告可以直接发给团队其他人看不需要他们再装Locust环境。生产环境里我还常用一个参数--stop-timeout 30。它控制的是在到达--run-time之后优雅停止虚拟用户前等待的时间用来让已经开始的任务跑完。如果不设置Locust可能在任务执行一半时强行停止导致日志里出现大量被中断的请求影响失败率统计。4.3 报告怎么读才是关键一个很多人会犯的错只看平均值。平均响应时间是一个很欺骗性的指标——接口偶尔延迟3秒但绝大多数请求是50ms平均值可能就只有70ms看起来一切正常实际上用户体验已经很差了。我通常按这个顺序读报告第一看RPS每秒请求数是不是达到预期目标。第二看失败率任何一种失败超时、TCP连接被重置、HTTP 5xx都要定位原因。第三看P95、P99相比P50的放大倍数如果P95是P50的5倍以上说明系统存在明显的长尾延迟。第四把RPS曲线和P95曲线放在一起看找到两者交叉的区域——这个区域往往就是系统吞吐的瓶颈点。压测做完之后经常要回答一个问题系统能扛多少并发我的回答从来没有一个数字。因为能扛取决于你对延迟的容忍底线。同样是500并发如果P95在200ms以内是能扛如果P95在5秒以上就算不能扛。所以报告里一定要同时标注目标和实测不要只给一串平均值。5. 分布式压测主从模式配置和真正的瓶颈来源5.1 什么情况下你才需要分布式单机Locust一个进程能跑几千协程那么在什么情况下需要考虑分布式目标QPS远高于单机能生成的范围比如网关接口目标QPS过万。压测目标机器的带宽和CPU受限于压测机本机需要分散压力源。业务脚本里本身有复杂的CPU计算比如签名、加解密每个协程占用CPU时间过长单进程的并发上限被压缩。我遇到的最典型的例子是压测一个带AES-256解密验签的网关接口单机2000个虚拟用户时压测机自己CPU跑满100%后端服务还没到瓶颈瓶颈出现在压测机上了。这种情况不上分布式不行。5.2 主从模式的启动方式分布式压测的架构是一个master节点负责调度和汇总结果N个worker节点负责实际发送请求。# master节点启动 locust --host https://api.example.com --master --master-bind-host 0.0.0.0 --master-bind-port 5557 # worker节点启动可以在不同机器上 locust --host https://api.example.com --worker --master-host192.168.1.100 --master-port5557启动之后在master的Web界面上能看到所有worker在线设置好用户数和启动速率master会把用户分发到各个worker上执行。分布式模式下的用户数是全局的。比如你设置2000个虚拟用户有两台worker那么每台worker上大约跑1000个虚拟用户。你可以通过--master界面的Worker列表面板确认这一点。这里有几个实战中的细节worker和master之间通过消息传递默认端口是5557如果跑在云上安全组要放通这个端口。master节点不发送任何压测请求它只做任务分发和结果汇总。如果worker节点上的脚本和master不一致包括函数名、类名、任务权重worker会收到切换任务失败的错误。所以我每次改动脚本后都要同时同步到所有worker。5.3 分布式的三个隐藏瓶颈分布式不是无脑加机器就完事有几个隐藏瓶颈值得先说清楚。首先是用户数据在多worker间的隔离问题。如果你的脚本从同一个CSV文件里读账号且每个worker启动时随机选择账号可能出现两个worker选到同一个账号导致服务端登录冲突。解决办法是按worker序号分片让每个worker读取CSV文件中对应该worker的区间保证数据不重叠。import os import csv # 假设每个worker有一个环境变量WORKER_ID从0开始 worker_id int(os.environ.get(WORKER_ID, 0)) worker_num int(os.environ.get(WORKER_NUM, 1)) with open(users.csv) as f: rows list(csv.reader(f)) my_rows [row for i, row in enumerate(rows) if i % worker_num worker_id]其次是master节点本身可能成为瓶颈。压测过程中所有worker会把每个请求的统计数据实时上报给master如果请求量非常大master节点上的网络带宽和消息处理会成为新的瓶颈。压测时我会单独观察master机器的CPU和内存占用如果master的CPU持续超过80%说明汇总链路已经吃紧了要么减少worker数量要么放宽统计上报的频率。最后是网络链路阻赛的干扰。分布式压测的多个worker如果在不同机柜、不同机房他们到目标服务的网络延迟本身就是不一致的。压测结果里的响应时间统计会包含跨机房的固定网络开销这会让P99被拉高。所以大规模分布式压测我一般建议worker和被测服务部署在同一内网避免跨公网压测导致的数据失真。6. 进阶玩法自定义负载策略、断言和持续集成6.1 用LoadTestShape实现阶梯加压别一步到位默认的压测模式固定了用户数和每分钟启动速率。有时候我们想模拟更复杂的负载曲线先让500个用户在2分钟内启动稳定5分钟然后在医疗器械3分钟内升到1000个用户再稳定5分钟最后一步步退。这种阶梯式加压在Locust里有内置支持。from locust import LoadTestShape class StepLoadShape(LoadTestShape): time_limit 1800 def tick(self): run_time self.get_run_time() if run_time 120: return (500, 10) elif run_time 420: return (500, 0) elif run_time 600: return (1000, 8) elif run_time 900: return (1000, 0) else: return Nonetick方法在每个时间点都会被调用返回一个(user_count, spawn_rate)元组表示当前阶段的目标用户数和启动速率。返回None表示停止压测。这个类的好处是整个压测过程不需要人工干预一次性跑完并且能形成完整的阶梯曲线方便观察系统在哪个阶段开始出现拐点。我自己实际过程中发现阶梯式加压对定位容量拐点非常有帮助。如果系统在800用户时P95还在100ms以内但900用户时突然飙到2秒这个断崖式下跌在阶梯图上非常直观。6.2 断言和失败归类让报告能直接给结论默认情况下Locust只把异常和HTTP非2xx响应记为失败。但在业务压测里状态码是200不代表业务逻辑成功。比如一个订单接口返回200但code字段是50001业务上其实是失败的。我会在脚本里做业务断言from locust import HttpUser, task, between class OrderApiUser(HttpUser): wait_time between(0.5, 1.5) task def create_order(self): with self.client.post( /api/order/create, json{sku_id: A1001, quantity: 1}, catch_responseTrue, ) as resp: data resp.json() if data.get(code) ! 0: resp.failure(fBusiness error: {data.get(message)}) elif resp.status_code ! 200: resp.failure(fHTTP {resp.status_code})报告里除了HTTP错误还会出现Business error这类业务失败明细这对研发定位问题非常高效。6.3 跑在CI流水线里压测结果自动化判断分布式压测做完之后脚本化、自动化和阈值判断往往是一套连招。把它集成到GitLab CI或者Jenkins里最关键的一步是能够自动判断这次压测是成功还是失败。Locust没有内置的断言机制但命令行提供了--exit-code-on-error参数它控制的是在运行时如果出现了失败异常或断言失败进程以非0码退出。默认情况下进程是以0码退出不管压测结果如何这就导致CI流水线没法自动判断。设置成locust --headless --host http://target.example.com -u 100 -r 10 --run-time 5m --exit-code-on-error 1只要有失败请求进程就会返回非0码CI流水线自动标记失败。不过这个判断颗粒度太粗了。我是更倾向于写一个后处理脚本解析CSV报告然后判断多个阈值条件。比如import csv import sys with open(result_stats.csv) as f: reader csv.DictReader(f) for row in reader: if row[Name] /api/order/create: p95 float(row[95%]) fail_ratio float(row[Failure %].strip(%)) if p95 200: print(fP95 too high: {p95}ms) sys.exit(1) if fail_ratio 0.01: print(fFailure ratio too high: {fail_ratio}%) sys.exit(1)这样CI阶段的判断标准就和业务目标强关联P95不能超过200ms失败率不能超过1%。如果这次压测只关注吞吐量就把RPS也加进判断条件。阈值没有通用值每个系统不同但逻辑结构是完整的。7. 实战中踩过的坑和规避方法一份排查清单7.1 压测机自身资源成为瓶颈很多人忽略了压测脚本里加密解密、签名计算对CPU的消耗。如果你的接口每个请求都要做一次RSA签名压测机的CPU会先于被测系统被打满。判断方法是压测时在压测机上看一下top——如果用户态CPU占用接近100%说明脚本本身太重了压测结果反映的是压测机的性能上限而不是服务端的性能上限。遇到这种情况我的做法是把签名运算从虚拟用户协程里挪到一个独立的预热阶段完成把签名结果缓存到全局字典里请求时直接取。这样压测机的CPU占用能明显降下来。如果业务逻辑不允许缓存那就只能通过分布式压测把计算压力分散到多台机器上。7.2 本机连接数限制和内核参数Linux单进程能打开的socket数量不是无限的默认的ulimit -n通常是1024对压测来说远远不够。如果不改压测刚开始就会出现一堆[Errno 24] Too many open files的错误很多人误以为是目标服务挂了其实是压测机自己的连接数被打满了。压测前在压测机上执行ulimit -n 1048576 sysctl -w net.ipv4.ip_local_port_range1024 65535 sysctl -w net.ipv4.tcp_tw_reuse1 sysctl -w net.ipv4.tcp_fin_timeout15ip_local_port_range是分配给本机发起连接时使用的端口范围默认从32768开始总共才3万多一点对于一个高并发的压测机来说可能不够用。tcp_tw_reuse和tcp_fin_timeout是调整TIME_WAIT状态的快速回收压测结束时可以看到大量TIME_WAIT连接这些都是主动关闭连接留下的不调整的话端口可能被占满导致后续连接无法建立。7.3 被压服务前的负载均衡或网关成为隐藏瓶颈有一次压测遇到一个诡异的情况直接把服务部署的实例扩容到了10个压测结果却显示RPS始终上不去而且三台压测机同时打着同一个被压域名。后来排查发现问题是入口的Nginx配置的worker_connections默认只有1024而这是被压服务的前置网关。这种场景非常典型。压测结果不好时排查链路应该是压测机到网关的连接是否建立了网关到后端服务的连接池是否够用网关的keepalive是否开启服务端的TCP backlog是否足够有时候我们要压的是单个微服务但压测请求需要经过API网关、鉴权服务、路由层任何一层性能不够压测结果都是在测那一层的上限而不是被测服务的上限。如果你只想压测一个具体的后端服务最好的方式是绕过网关直接用内部服务地址去压这样才能得到这个服务的真实容量。压测网关本身是另一个场景要把两个场景分开来看。7.4 gevent和常见Python库的兼容性Locust底层是gevent而gevent会把标准库的网络调用patch成非阻塞模式。如果你的压测脚本里用到了某些不走标准库的第三方HTTP客户端比如httpx或者用了自己封装的Socket连接可能会出现请求卡住不返回或者行为奇怪的问题。最稳妥的做法是所有网络请求都通过self.client发它是gevent兼容的。另外不要在主协程里做需要等待大量任务完成的同步操作比如time.sleep虽然它在gevent下也有效但它会让当前协程挂起影响任务调度精度。需要等待的话可以用gevent.sleep它和协程调度器的结合更紧密。7.5 分位数口径不要搞混报告里的50%、95%、99%是响应时间的百分位但注意Locust的统计逻辑是基于聚合周期的——默认每2秒记录一个采样点然后合入全局统计。如果你在压测中还需要关注某个时间段的极值光看最终报告是看不出突刺的要配合stats_history.csv文件里的时间序列数据来分析。我曾经在处理一个P99飙升的问题时只看最终报告觉得还行后来拉了时间序列文件才发现某个3秒的窗口内P99高达8秒而后面的采样点把它稀释了。这种瞬时突刺在最终报告里几乎看不出来但对线上用户的直接影响是巨大的。7.6 主从模式下任务不一致的典型报错分布式模式时最容易出的报错是worker received incorrect message, could not unpack这个报错十有八九是master和worker节点的Locust版本不一致。两个节点执行locust --version把版本统一成同一个就解决了。还有一种情况是worker节点启动时没有传--host参数虽然任务分发时会带上目标地址但有时会因为host缺失报一些莫名其妙的错误。建议所有worker节点都显式传--host避免不必要的麻烦。写在最后压测这事做久了你会越来越清楚一个道理工具只是手段压测的价值在于让系统在真实流量到来之前暴露出它最脆弱的地方。Locust最大的优势不是它比JMeter功能更多、比wrk性能更高而是它用Python把压测脚本的门槛降到了最低——你不需要额外学一套技能只要会写Python就能把业务逻辑复刻到压测场景里。我最后再分享一个自己的习惯正式压测跑之前我总会先用--headless -u 1 -r 1 --run-time 30s跑一遍全流程脚本确认每个任务都不报错而且观察一次完整请求的响应时间。这一步虽然简单但能在真正压测前过滤掉80%的脚本低级问题。如果你的项目中还没有引入Locust我建议从一个小接口、一次小规模压测开始试水别一上来就搞分布式。等熟悉了它的模型、读得懂图表了再逐步把压测推广到核心业务链路里。这个框架的快乐是实实在在的越用越顺手。
返回列表