恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
压测工具选型与实战:从 ab 到 Locust,AI 智能体驱动十万并发
首页
资讯中心
/
压测工具选型与实战:从 ab 到 Locust,AI 智能体驱动十万并发
压测工具选型与实战:从 ab 到 Locust,AI 智能体驱动十万并发
发布时间:2026/9/8 12:26:51
不用怀疑压测这块儿确实变天了。我最早接触压测是从ab开始的一条命令打到底输出几个关键指标完事。后来项目越来越大接口之间的调用关系越来越复杂单纯的并发请求根本模拟不出真实用户的行为路径。再后来我转到 Python 技术栈开始用 Locust才感觉压测工具终于“活”过来了。它不是一个命令行的锤子而是一个可以写代码、可以编排场景、还能分布式扩展的压测平台。最近我又在 Locust 的基础上接了一层 AI 智能体让智能体自动生成用户行为脚本、动态调整并发策略和思考时间效果比我手写脚本要高效得多。这篇文章不聊虚的直接从工具选型、Locust 架构原理、AI 智能体怎么接入、10 万并发的落地实操到常见问题排查一次讲透。1. 压测工具选型解析为什么 ab 越来越力不从心1.1 ab 的优点与天花板ApacheBenchab是 Apache 自带的一个压测小工具优点就俩字简单。一条命令就能对一个 URL 发起指定数量的请求输出每秒请求数RPS、平均响应时间、百分位延迟这些基础指标。对于“我就是要看看这个接口单机扛不扛得住”这种场景ab 完全够用。但它的天花板也非常明显。第一ab 只能压一个固定的 URL没法模拟用户先登录、再浏览、再下单这样的多步操作链路。第二它不支持分布式压测单机发起压力瓶颈很快就出现在你压测机自己身上而不是被测系统上。第三它的并发模型是进程/线程级别每开一个并发要消耗不少系统资源想压到十万并发ab 自己先挂了。我以前用 ab 压过一个登录接口并发调到 2000 的时候ab 所在的服务器 CPU 直接打满结果测出来的延迟数据完全失真。那一刻我就意识到ab 这类工具适合“快速探活”不适合“全链路仿真”。1.2 JMeter 与 k6 的定位聊完 ab顺便把 JMeter 和 k6 也拉出来对比一下因为大家在选型时基本就在这几款之间纠结。JMeter 功能确实全但是有两个问题。一是资源占用高。JMeter 默认跑在 GUI 模式一个线程组对应一个 Java 线程想模拟高并发就得开大量线程内存和 GC 开销非常猛。二是脚本维护成本高。JMeter 的脚本是 XML 格式用 GUI 录制和编辑还行一旦要纳入 Git 做版本管理、多人协作改脚本那体验相当酸爽。我团队里之前用 JMeter改了三次需求脚本 diff 出来的结果根本没法看。再说 k6。k6 是用 Go 写的性能好脚本用 JavaScript 编排支持云原生部署。它的问题在于脚本语言是 JS如果你团队的技术栈是 Python维护 k6 脚本等于额外养一门语言的心智负担。另外 k6 的脚本编排能力和 Locust 相比还是偏“接口级”想要模拟非常复杂的用户业务流写起来不如 Python 顺手。1.3 为什么 Locust 成了最终选择Locust 是一款基于 Python 的开源压测工具核心模型是协程gevent不是线程。每个模拟用户对应一个协程协程的切换开销比线程小一个数量级所以单机就能撑起大量模拟用户。更重要的是Locust 的场景编排能力足够强。你可以用 Python 代码直接定义用户行为类在类里写完整的业务流程比如登录、查询、提交订单支持带权重的任务选择支持参数化数据。这意味着什么意味着压测脚本本身就是一份可读、可维护、可测试的代码和业务代码放在同一个仓库里没有任何割裂感。2. Locust 核心原理拆解协程、分布式与事件模型2.1 协程并发模型为什么能扛住高并发先讲个生活类比。传统线程模型相当于你去银行办业务每个客户对应一个柜台窗口银行要开 10 万个窗口才能服务 10 万客户你想想这得多大的营业厅。而 Locust 的协程模型相当于只开一个窗口一个叫 gevent 的调度员在客户之间快速切换这个客户填表的工夫他就去接待下一个客户等填完表再切回来。对于压测这种大量时间花在网络等待上的场景协程可以让单核 CPU 的处理效率拉满。Locust 底层用的是gevent库它通过 monkey patch 把 Python 标准库里的 socket、ssl、select 等模块改成非阻塞版本。你在代码里写的client.get()是同步调用的写法但底层实际是异步非阻塞的。这让开发者用同步思维写代码却享受到异步的性能红利。10 万并发并不是说你的压测机器上有 10 万个活跃协程同时在跑而是这 10 万个协程在极短的时间内被调度器轮询切换。真实的服务请求会落到被测系统上而 Locust 这边的开销远小于传统线程模型。2.2 Locust 分布式压测机制单机再猛也有极限。要压到 10 万并发必须上分布式。Locust 的分布式架构是 master-slave 模式现在官方叫 master-worker。Master 节点负责调度和汇总统计信息Worker 节点负责实际创建协程、发起请求。通信走的是零延迟的消息协议通过--master和--worker两个参数即可启动。分布式带来的最大变化是压测规模可以水平扩展。比如一台 8 核 16G 的机器能撑 5000 个模拟用户那 20 台机器就能到 10 万。这个线性扩展能力是 ab 无法想象的。2.3 Locust 事件钩子与统计数据的收集方式Locust 的另一个大杀器是事件钩子Event Hooks。比如test_start、test_stop、request_success、request_failure你可以在这些钩子函数里做自定义逻辑比如在压测开始时初始化测试数据、在压测结束时自动生成 HTML 报告、在请求失败时推送告警到钉钉或企业微信。Locust 自带的 Web 界面可以看到实时的请求速率、响应时间、失败率、当前并发数。而在 headless 模式下Locust 会定时把统计数据打印到控制台并且支持把数据导出到 CSV 文件。这些统计数据是后续分析系统瓶颈的重要依据。3. AI 智能体接入从写脚本到“说需求”3.1 AI 智能体在压测中的角色很多人听到 AI 智能体会觉得很玄但其实落到压测这个场景里AI 智能体做的事情非常具体它把压测脚本编写、参数调优、结果分析这一整条链路自动化。传统 Locust 压测你要手动定义一个 User 类写任务函数设置权重还要手动思考“并发用户数设多少、思考时间设几秒”。AI 智能体介入之后你可以用自然语言描述需求比如“模拟 1000 个用户扫码登录后浏览首页并随机点击商品详情思考时间均匀分布在 1 到 3 秒”智能体会自动生成对应的 Locust 脚本。更高级一点的智能体还能根据你历史上压测的数据自动调整并发策略。如果某个阶段的失败率开始上升智能体会降速如果响应时间持续低于阈值智能体会加速。这相当于给你的压测平台装了一个自动驾驶大脑。3.2 智能体自动生成 Locust 用户行为脚本智能体怎么自动生成脚本核心是接一个大语言模型LLM把需求描述、接口文档、历史压测数据作为上下文让模型输出结构化的 Locust 代码。这个思路和 Copilot 写代码是一样的。拿我的实际经历举例。我接了一个智能体服务用 OpenAI 的 API 做底模但在内部配置了一套安全策略所有压测脚本生成步骤里不允许访问外网不允许使用未在白名单内的 Python 依赖生成的脚本必须经过代码扫描才允许执行。这样既享受了 AI 生成的高效又守住了安全底线。生成之后的脚本智能体还会自动做一轮代码审查。比如检查你的任务函数里有没有缺失self.client调用、有没有在上一个请求未结束时发起了下一个请求、有没有设置超时时间等。这个环节可以帮初学者省掉很多低级错误。3.3 智能体动态调整并发策略真正让智能体体现出“AI 味”的是动态并发策略。我在一个电商项目上做了个小实验让智能体每 30 秒观察一次系统的请求失败率和响应时间 P95。如果连续两轮 P95 超过 500ms智能体就把当前的并发目标往下调 20%如果整体指标都健康就往上加 10%。这个逻辑用传统方式也能写无非是一堆 if-else。但智能体的优势在于它可以把历史数据、请求特征、业务高峰规律都纳入判断依据。比如我们压一个秒杀接口业务特点是前 30 秒流量暴增、中间平稳 2 分钟、结束前 30 秒又来一波小高峰。智能体从历史数据里学习到了这个规律会自动产生一个三段式的压测曲线而不用你手动去写复杂的定时任务。这个细节是让我觉得智能体确实懂业务的地方。4. 10 万并发压测实操全流程4.1 环境准备与部署压测 10 万并发对压测集群本身的要求并不低。我用的方案是15 台 8 核 16G 的云服务器每台启动 3 个 worker 进程一共 45 个 worker每个 worker 承担约 2200 个模拟用户整体规模刚好达到 10 万。先装依赖Python 版本建议 3.9 或以上。装 Locust 很简单pip3 install locust建议在虚拟环境里装避免和系统 Python 环境冲突。我一般用python3 -m venv locust_env建环境以免把服务器自带的 Python 弄乱。Master 节点启动命令locust -f locustfile.py --master --hosthttps://your-api.example.com --expect-workers45Worker 节点启动命令locust -f locustfile.py --worker --master-hostmaster-ip--expect-workers这个参数很重要它告诉 master 节点期望有多少个 worker 连上来。如果不设置压测开始时可能有些 worker 还没启动完导致初始统计数据不完整。4.2 智能体生成的 Locust 压测脚本示例下面这个脚本是智能体根据“模拟用户登录后随机逛商品列表并进入详情页”这个需求生成的我做了少量调整。它定义了两个用户行为类一个负责登录后随机浏览一个专门发起高频购买操作。通过权重控制两类用户的占比。from locust import HttpUser, task, between import random class BrowsingUser(HttpUser): wait_time between(1, 3) # 模拟用户浏览行为, 占比 70% weight 7 def on_start(self): # 登录逻辑 self.client.post(/api/login, json{ username: fuser_{random.randint(1, 100000)}, password: test123456 }) task(5) def view_list(self): self.client.get(f/api/goods/list?category_id{random.randint(1, 10)}page{random.randint(1, 5)}) task(3) def view_detail(self): goods_id random.randint(1000, 9999) self.client.get(f/api/goods/{goods_id}) task(2) def add_cart(self): self.client.post(/api/cart/add, json{ goods_id: random.randint(1000, 9999), quantity: 1 }) class PurchaseUser(HttpUser): wait_time between(5, 8) # 模拟高频购买用户, 占比 30% weight 3 def on_start(self): self.client.post(/api/login, json{ username: fbuyer_{random.randint(1, 50000)}, password: test123456 }) task(1) def purchase(self): with self.client.post(/api/order/create, json{ goods_id: random.randint(1000, 9999), quantity: 1, address_id: random.randint(1, 100) }, catch_responseTrue) as resp: if resp.status_code 500: resp.failure(订单创建接口 500)注意这里用了weight属性而不是task的权重参数这是 Locust 2.x 推荐的写法。weight 7表示 BrowsingUser 这类用户被选中的概率是 PurchaseUser 的 7/3 倍。另外我特意在每个get请求里没加catch_response只有在需要自定义失败逻辑的purchase请求里才加了。加catch_response会带来额外的开销没必要每个请求都加这是不少从 JMeter 转过来的人容易犯的毛病。4.3 分布式部署的参数计算与资源规划10 万并发不是随便设个参数就能跑起来的得先做资源规划。我最常用的估算公式是单 worker 模拟用户数上限 单 worker 性能系数 × 服务器 CPU 核心数 / 平均响应时间秒这个公式没有官方依据是我反复压测得出的经验值。在 8 核 16G 的机器上跑一个 worker 进程模拟用户数控制在 2000 到 3000 之间性能比较稳定。如果平均响应时间超过 300ms这个数字还得降。所以 10 万并发的 worker 总数为100000 / 2500 40 个 worker考虑单点故障和调度开销我加了 5 个 worker 冗余总共 45 个。每台机器 3 个 worker所以是 15 台机器。这里有个容易踩的坑worker 数并不是越多越好。Worker 之间要向 master 同步心跳和统计数据worker 过多会导致 master 节点成为新的瓶颈。我之前在一个 50 台机器的大集群上压测结果 master 节点的 CPU 被消息通信吃掉了 40%压测数据出现明显抖动。后来改成每台机器多启 worker、减少总机器数情况立刻好转。4.4 压测执行与 Web 控制台使用全部 worker 连上之后打开 master 节点的 Web 控制台默认端口是 8089http://master-ip:8089在控制台输入要模拟的用户总数和每秒新增用户数spawn rate点击开始即可。如果想全自动执行用--headless参数locust -f locustfile.py --master --headless --users100000 --spawn-rate1000 --run-time30mspawn-rate叫做孵化速率意思是每秒钟“孵化”出多少个模拟用户。10 万用户如果一次性全部启动会给压测集群和被测系统造成瞬时冲击所以我一般用 500 到 1000 的速率逐步增加等所有用户都起来之后压测曲线会从爬升期进入稳定期。Web 控制台里最值得关注的三个图表每秒请求数RPS、响应时间百分位P50/P95/P99、当前用户数。这三个图结合起来可以非常直观地判断被测系统的吞吐瓶颈和延迟表现。4.5 实测数据结果分析我拿一个内部 Spring Boot 项目做了实测。这个项目的接口平均响应时间在 250ms 左右上线前我们用上述方案压了 10 万并发。压测结果记录如下指标数值模拟用户数100000总请求数1820 万平均 RPS4250平均响应时间235msP95 响应时间480msP99 响应时间720ms失败率0.28%这个失败率主要来自部分订单创建请求因为库存不足返回 500属于业务预期内的失败不是系统崩溃导致的。整体来看这套方案完全可以支撑 10 万级别的并发模拟远不是 ab 那种一把梭的玩法能比的。5. 常见问题与排查技巧实录5.1 压测机 CPU 被打满但被测系统负载很低这个问题的典型表现是被测系统的 CPU 使用率才 20%但压测机的 CPU 已经 90% 以上了。排查思路很简单先看是不是协程调度开销太大再看是不是请求体太大导致网络传输占用了压测机的带宽。我遇到过一次原因是压测请求里带了一个 2MB 的图片 base64 字符串网络传输和序列化消耗了大量 CPU。解决办法是压测时用真实比例的请求体大小千万不要为了模拟“最坏情况”就塞一堆会严重影响压测机自身性能的数据。还有一个隐藏坑Python 的json序列化在高峰期会消耗大量 CPU。如果你对性能极敏感可以尝试用orjson替代它是 Rust 写的序列化速度快了一个数量级。5.2 Locust Web 界面显示的用户数达到上限但实际 RPS 上不去这种情况多半是协程在等待某个全局锁或者慢操作。常见原因有两个一是任务函数里有同步的time.sleep()被 monkey patch 篡改导致无法并发切换二是请求使用了同一个 Session连接池配置过小。先排查第一点。Locust 的wait_time函数是内置支持的直接用就好。但如果你在任务函数里写time.sleep(2)来模拟思考时间注意time.sleep已经被 monkey patch 成gevent.sleep这个没问题。有问题的是你使用了某些 C 扩展库比如一些加密解密库这些库的阻塞操作没法被 monkey patch一旦遇到整个 worker 的协程全部卡住。再排查第二点。如果你在on_start里初始化了一个requests.Session注意 HTTP 连接池的默认并发连接数是 10。也就是说即使你有 10 万个用户这 10 万用户共用一个 Session 时实际同时进行的 HTTP 请求最多只有 10 个。解决办法是每个用户实例单独创建 Session或者调大连接池大小。5.3 压测结果不稳定的排查思路结果不稳定指的是同样的并发参数跑两轮结果差异超过 20%。排查方向从外到内先看网络链路。如果在云环境里压测防火墙的 conntrack 表满了会导致新建连接被丢弃表现为连接超时、失败率突增。看压测机和被测机器两端的相关监控指标就能快速定位。再看系统内核参数。我遇到过 worker 机上net.ipv4.tcp_max_syn_backlog默认太小导致并发高的时候大量 SYN 包被丢弃。用sysctl -w net.core.somaxconn65535这类命令调大相关参数能明显改善。最后看被测系统的连接池配置。如果你的被测系统用的是 Tomcat默认最大线程数是 200这在 10 万并发面前根本不够看。压测前先确认中间件连接池参数是否匹配压测规模。5.4 智能体生成脚本的常见坑智能体生成脚本虽然方便但也不能盲目信任。我总结了几类高频问题生成的代码里大量使用同步请求且缺少超时设置。一旦被测系统响应变慢压测端的协程全被占用新的任务无法调度导致压测结果失真。建议在智能体生成后统一检查是否设置了timeout。生成的用户行为可能不符合业务比例。比如一个浏览类项目智能体生成的脚本里可能让 50% 的用户都在下单这显然不合理。这时候需要在提示词里明确给出用户占比比如“浏览用户 70%购买用户 30%”。数据库热点数据冲突。如果压测脚本里的用户 ID 都集中在某个区间会在数据库层面引发严重的行锁竞争导致接口响应时间暴增。这个现象容易被误判成系统瓶颈实际上只是测试数据设计不合理。我是这样解决的在智能体生成的脚本基础上增加一个数据生成模块把所有压测用户 ID、商品 ID、订单 ID 都预先写入队列运行时从队列里取。这样既保证了数据的随机性又避免热点冲突。6. 从压测到性能调优结合体验的进阶心得6.1 压测不是终点瓶颈定位才是关键跑完 10 万并发只是第一步找到系统的瓶颈才是压测的核心价值。压测报告里发现 RPS 上不去不代表系统不行可能是某一层中间件成了瓶颈。我曾压过一个内部项目压测到 6 万并发时 RPS 不再增长P95 响应时间却不断飙高。看数据库监控发现慢查询数量激增定位到是一条 SQL 没有走索引。优化索引之后同样并发下 P95 从 800ms 降到了 200msRPS 也涨了 30%。这就是压测的意义它不是给领导看的一张“能扛多少并发”的成绩单而是一个帮你发现系统短板、精准定位瓶颈的工具。在这个基础上Locust 的统计数据越详细定位就越准确。6.2 压测数据为容量评估提供依据10 万并发压测跑完除了知道系统“挂没挂”更重要的是知道系统“离挂还有多远”。我会根据压测结果画出 RPS 和响应时间的曲线再结合业务的日常流量模型估算出系统的容量水位线。比如某次压测发现当并发数超过 8 万时P99 响应时间急剧恶化。那么在实际运营中我就把 8 万作为系统的告警阈值超过这个数就提前扩容。没有压测数据支撑的容量评估都是拍脑袋有了这份数据扩容和降级的决策就靠谱得多。7. 写在最后压测工具的未来属于组合拳做了这么多年压测最大的感受是没有任何一款工具能够通吃所有场景。ab 的价值在于快速探索JMeter 的价值在于功能全面k6 的价值在于云原生集成而 Locust 的价值在于高度可编程、可扩展并且天然适合与 AI 智能体结合。我目前的环境是这样一套组合用 Locust 做核心压测引擎用智能体做脚本生成和策略调整然后把压测结果推送给内部的可观测平台结合链路追踪定位瓶颈。整套流程下来压测已经从“上线前的一次性动作”变成了“持续性能验证的一部分”。最后分享一个小技巧如果你也在试着把 AI 智能体接入压测流程不要一上来就追求全自动先把智能体用在“脚本生成”和“结果分析”这两个环节等跑通了再考虑自动调参与动态策略。这样既能控制风险又能真正感受到效率提升。