系列12-接口压测怎么做成平台能力?自研 httpx 引擎、分布式 Worker 与 Locust 选型对照
团队做性能测试,常见两条路:
- Locust / 自写脚本:灵活,但 URL/Body/Token 与接口回归两套维护,报告散落本地 HTML
- JMeter GUI:功能全,但 XML 难维护,CI 集成重
BrickCore 选第三条:复用接口自动化用例(ApiTestCase)+ asyncio/httpx 自研压测引擎,可选Perf Worker水平加并发。
需要先说清一点:平台没有嵌入 Locust,Docker 镜像也不带 Locust 依赖;执行层借鉴 Locust 的并发用户 / Ramp-up / 分布式 Worker产品思路,HTTP 请求与变量替换与run_single_case同源(build_perf_request→ httpx)。
演示与源码
| 地址 | |
|---|---|
| 功能演示 | http://43.142.83.156/showcase/ (性能测试相关说明见文档中心;平台 admin / BrickCore123456) |
| 开源仓库 | https://gitee.com/BanZhuanKeOrz/BrickCore |
线上路径:性能测试 → 场景管理 / 执行机 / 执行记录。Worker 推荐BrickCoreRunner v1.3.14+选「压测执行机」角色上线。
一、平台化压测要解决什么
| 脚本压测痛点 | 平台化做法 |
|---|---|
| Swagger 已导入,压测又要抄一遍 URL | 场景引用已有 ApiTestCase |
| 测试/预发 Host、Token 各写各的 | Environment + Token 授权 + merge_execution_variables |
| 报告不在统一看板 | PerfRecord落库 + 曲线 + 多轮对比 |
| 单机并发不够 | Perf Worker注册、按比例拆并发 |
| 大模型 SSE 接口只看总 RT | stream_burst+qa_sse_v1阶段指标 |
二、架构一图读懂
PerfScene(场景:scene_items + config + csv) ↓ POST /perf/exec/{scene_id}?use_workers= PerfRecord(config_snapshot 不可变快照) ↓ run_perf_scene(BackgroundTasks) ┌─────────────────┬──────────────────────────┐ │ 本机 asyncio │ 分布式 use_workers=true │ │ Backend httpx │ distribute_concurrent │ │ 虚拟用户协程池 │ → Perf Worker(perf_worker)│ └─────────────────┴──────────────────────────┘ ↓ 秒级聚合 time_series_data 报告:QPS / P95 / error_rate / case_aggregations / phase_metrics与 UI Runner 分工:Perf Worker 只跑HTTP 压测;UI Runner 跑 Playwright,队列协议不同(系列09)。
三、数据模型
PerfScene ├─ scene_items: [{case_id, weight, delay_ms}, ...] ├─ config: {mode, concurrent_users, ramp_up_seconds, ...} └─ csv_data + csv_config PerfRecord(一次执行) ├─ config_snapshot / scene_items_snapshot ├─ total_requests, qps, p95, error_rate, time_series_data ├─ case_aggregations(接口维度) ├─ phase_metrics / request_details(SSE 场景) └─ distribution_info(分布式 Worker 分配) PerfWorker ├─ register / heartbeat / unregister ├─ max_concurrent └─ project_id(须与场景项目一致)快照设计:场景事后被改,历史报告仍对应当时的配置与用例列表——发版对比靠record_id,不靠「还记得上次参数」。
四、五种压测模式
| mode | 说明 | 典型场景 |
|---|---|---|
fixed | 固定并发 + 持续时长(秒) | 稳态容量验证 |
loop | 固定并发 + 每用户循环 N 次 | 固定请求总量 |
stepping | 多阶段递增并发与时长 | 梯度加压、找拐点 |
stream_burst | 每虚拟用户1 次SSE 流式请求,采集问答各阶段耗时 | 大模型 / 流式 API |
journey_fixed/journey_loop | 业务链路:多阶段顺序执行,步骤间 extractors 传参 | 登录→业务接口 |
固定/循环/梯度模式还可勾选流式问答:在持续压测中对指定用例走 SSE 引擎(use_stream_execution)。
场景项示例(权重 + 思考时间,概念对齐 Locust@task(weight)+between):
[{"case_id":101,"weight":3,"delay_ms":500},{"case_id":102,"weight":1,"delay_ms":0}]配置示例:
{"mode":"fixed","concurrent_users":50,"ramp_up_seconds":10,"duration_seconds":120,"error_rate_threshold":5,"request_detail_level":"brief"}error_rate_threshold:错误率连续 3 秒超阈值自动停压(workers.py中ERROR_RATE_AUTO_STOP_MSG)。
五、执行链路(源码)
5.1 启动
# routers/perf/exec.py — start_perfrecord=awaitPerfRecord.create(scene_id=scene_id,status="pending",trigger_type="manual",config_snapshot=config,scene_items_snapshot=scene.scene_items,)background_tasks.add_task(run_perf_scene,record.id,use_workers)5.2 run_perf_scene 核心步骤
- 读快照,解析
env_id、Host(可target_host覆盖环境) - Host 连通性探测(HEAD),失败则
record.status=failed - 预加载
ApiTestCase+ApiDefinition,merge_execution_variables合并项目/环境变量 - 构建
scene_items_for_worker(含 merged headers/body,减少 Worker 侧查库) - 分支:本机 asyncio或分布式 Worker
5.3 本机:虚拟用户 + 信号量
# _perf_worker_fixed:random.choices(case_pool, weights=...) 按 weight 选接口asyncwithsem:# sem = concurrent_usersresult=await_execute_perf_case_request(case,env,target_host,client,csv_row,...)ifdelay_ms>0:awaitasyncio.sleep(delay_ms/1000)_execute_perf_case_request走 httpx,成功判定:status < 500 且断言通过(与功能回归同源断言逻辑)。
5.4 分布式:并发拆分
# routers/perf/workers.py — distribute_concurrent# 按各 Worker max_concurrent 比例分配,且不超过单节点上限assignments=distribute_concurrent(total_concurrent,workers)Worker 侧引擎与 Backend同一套runner/perf_worker.py(BrickCoreRunner 内置或命令行启动),秒级指标 POST/workers/{record_id}/report,结束后finalize汇总。
硬约束:journey_*模式若含阶段sync_before屏障,不支持分布式——引擎会直接 failed 并提示改单机执行(journey_has_sync_barrier校验)。
六、复用接口用例:变量与断言
压测不另写 locustfile,请求构建走build_perf_request:
all_variables=ensure_dt_cache(awaitmerge_execution_variables(case.project_id,env.id))# + csv_row 列 → ${{username}}# + journey 步骤间 session_variables(extractors)method,url,headers,params,body,timeout,body_type=...| 能力 | 说明 |
|---|---|
${{env_var}} | 与接口回归同一套替换 |
${{df:标签}}/${{dt:...}} | 数据工厂、插入工具 |
| CSV 列 | ${{username}}等 |
| 断言 | 压测仍执行;失败计入 error_rate(可弱化非关键断言) |
实操:压测前用接口用例单跑确认 Host、Token、Body;再挂到场景里加权。
七、CSV 参数化
csv_data存 JSON 数组,csv_config.strategy:
| strategy | 行为 |
|---|---|
round_robin | 虚拟用户轮询各行 |
unique | 每用户绑定一行(用户数 ≤ 行数) |
random | 随机取行 |
分布式下get_next_csv_row(..., worker_id, total_workers)避免多 Worker 抢同一行。
八、Perf Worker 部署(推荐 BrickCoreRunner)
8.1 客户端方式(推荐)
- 安装BrickCoreRunner v1.3.14+
- 登录 → 执行角色仅压测或UI + 压测
- 选择压测项目(与平台顶部项目 ID 一致)→上线
- 性能测试 → 执行机确认在线
- 场景执行勾选使用分布式 Worker
客户端会话区 +runner/logs/perf_worker.log可看秒级 QPS/RT;下线自动unregister,不必等心跳超时。
8.2 命令行(CI / 高级)
cdrunner python perf_worker.py--masterhttp://你的平台地址\--tokenmy-local-token\--name"压测机-01"\--max-concurrent200\--project-id 当前项目ID生产环境浏览器访问一般为80 端口(Nginx),--master不要写 :8000。
8.3 何时勾选 Worker
| 场景 | 建议 |
|---|---|
| 小并发冒烟、链路调试 | 不勾选,Backend 本机执行 |
| 高并发、多机叠加 QPS | 勾选 Worker |
| 无在线 Worker | 自动降级本机(cron 同理) |
九、流式 / SSE 与大模型压测
stream_burst模式 +stream_profile.parser_id(默认qa_sse_v1):
- 每用户一次完整 SSE 会话
- 采集:首字时间、思考耗时、各阶段 RT→
phase_metrics - 报告支持SSE 阶段汇总、流式明细懒加载、导出 Excel
request_detail_level=detailed可保留成功 trace,不影响 QPS/RT 聚合
固定/循环/梯度模式也可对指定用例勾选流式执行,适合「混合流量里夹 SSE 接口」。
十、业务链路(Journey)
journey_fixed/journey_loop:多phase顺序/并行,步骤间extractors → session_variables,等价压测版「登录→下单」:
{"mode":"journey_fixed","concurrent_users":20,"duration_seconds":300,"journey":{"phases":[{"name":"登录","execution":"serial","steps":[{"case_id":101,"delay_ms":0}]},{"name":"下单","execution":"serial","sync_before":false,"steps":[{"case_id":102,"delay_ms":200}]}]}}sync_before: true为阶段屏障(全链路用户齐步走)——仅单机;分布式请关闭或改journey_fixed单机压测。
十一、报告读什么
| 指标 | 说明 | 发版决策 |
|---|---|---|
| QPS / 成功 QPS | 吞吐 | 是否达 SLA |
| avg / P90 / P95 / P99 | 延迟分布 | 长尾是否恶化 |
| error_rate | 失败占比 | 对照阈值、自动停压 |
| time_series_data | 秒级曲线 | 是否「越压越慢」 |
| case_aggregations | 分接口统计 | 定位慢接口 |
分位采样说明:接口维度 P90/P95/P99 基于最多 5000 条RT 样本(蓄水池采样,MAX_CASE_RT_SAMPLES);总请求数、QPS、错误率、Min/Max 仍统计全量。超大规模压测时分位为近似值,报告页有说明。
支持多 record 对比、HTML 导出、完成后邮件/钉钉/企微推送(maybe_auto_push_perf_report)。
十二、与 Locust 选型对照
| 维度 | Locust 脚本 | BrickCore 平台压测 |
|---|---|---|
| 接口定义 | locustfile 手写 | 引用 ApiTestCase |
| 环境切换 | 改代码/环境变量 | 换env_id |
| 分布式 | master/worker | Perf Worker+ 比例分配 |
| 权重/间隔 | @task/between | weight / delay_ms |
| SSE 阶段 | 需自写解析 | stream_burst + qa_sse_v1 |
| 报告 | 本地 HTML | 落库 + 曲线 + 对比 + 通知 |
| 依赖 | Locust | asyncio + httpx(镜像更轻) |
外部仍有 Locust 脚本时,结果需自行对接;平台侧重与接口资产、定时任务、看板一体。
十三、发版前压测 SOP
- 场景:核心 3~5 个接口,
weight按生产流量比例 - 环境:独立压测环境,勿误打生产
- 冒烟:10 并发 × 60s 本机验证用例与 CSV
- 加压:
stepping或提高concurrent_users,勾选 Worker - 阈值:设
error_rate_threshold(如 5%) - 对比:与同场景上一版
record_id比 P95、error_rate - 归档:评审贴 record 链接;可选定时压测(
PerfCronJob+use_workers)
十四、常见排错
| 现象 | 原因 | 处理 |
|---|---|---|
| Host 不可达 | env.host 错 / 网络 | 检查环境;exec 前有 HEAD 探测 |
| Worker 不分配 | 无在线 / project_id 不一致 | 执行机页看 heartbeat;Runner 选对项目 |
| 分布式启动 failed | journey + sync_before | 关屏障或单机 |
| error_rate 100% | Token/Body 错 | 接口用例单跑通过再压 |
| QPS 很低 | delay_ms 大 / 断言过重 / 瓶颈在被测方 | 调参;看 time_series |
| 与 Locust 数值差 | 连接复用、模型不同 | 看趋势与相对对比,不必抠绝对值一致 |
| 分位与 Locust 差很多 | 5000 样本蓄水池 | 看全量 QPS/错误率;知悉分位为近似 |
十五、小结
- 平台压测 =ApiTestCase 资产 + asyncio/httpx 自研引擎,不是嵌入 Locust。
- 五种模式覆盖稳态、梯度、SSE、业务链路;快照保证报告可追溯。
- Perf Worker与 Backend同引擎,
distribute_concurrent按容量比例拆并发。 - CSV + 变量合并与接口回归同源;报告支持对比、SSE 阶段、自动停压与通知。
附录 A:源码文件索引
| 顺序 | 文件 | 关注点 |
|---|---|---|
| 1 | models/perf.py | PerfScene / PerfRecord / PerfWorker / PerfCronJob |
| 2 | routers/perf/exec.py | start_perf、run_perf_scene、各 mode worker |
| 3 | routers/perf/workers.py | register、distribute_concurrent、秒级上报 |
| 4 | modules/perf/perf_journey.py | 链路编排、sync 屏障 |
| 5 | modules/stream_phase/ | SSE 解析、stream_burst |
| 6 | runner/perf_worker.py | 分布式 Worker 执行引擎 |
| 7 | routers/perf/cron.py | 定时压测、use_workers降级 |
选型背景(docs/ROADMAP.md):零 Locust 依赖、直接复用接口用例变量/断言,Docker 部署更轻。
支持与交流
- 演示:http://43.142.83.156/showcase/ · 源码:https://gitee.com/BanZhuanKeOrz/BrickCore
- 觉得有用欢迎Star⭐,问题评论区留言或 Gitee Issues