Sim 工作流异步执行压测指南:用 Artillery 验证队列与并发隔离
【免费下载链接】simSim is the collaborative workspace to build, deploy, and monitor AI agents and workflows. Used by 100,000+ builders.项目地址: https://gitcode.com/GitHub_Trending/sim16/sim
本篇技术指南围绕 Sim 仓库内置的本地压测场景(apps/sim/scripts/load/)展开,讲解如何针对POST /api/workflows/[id]/execute异步执行接口进行基线并发、队列冲击波与跨工作空间隔离三类压测。读完本文,你将掌握各场景的默认参数、全部可调环境变量、底层准入控制(Admission Gate)的工作原理,以及如何根据429/ETIMEDOUT结果调整压测强度。
压测前置条件与环境准备
这些 Artillery 场景是本地专用(local-only)的,全部针对POST /api/workflows/[id]/execute的异步模式(async mode)进行施压。开始前需要满足三项要求:
- 本地运行应用:使用仓库根目录
package.json中定义的dev:full脚本启动完整开发环境(同时拉起 App 与 Realtime 两个进程):bun run dev:full仓库中还提供了
dev:full:capped变体(package.json),可在需要限制本地资源时使用。 - 有效的工作流 ID 与 API Key:每个场景都需要传入目标工作流的
WORKFLOW_ID以及对该工作流所在工作空间有执行权限的 API Key。 - 默认目标地址:所有场景默认请求
http://localhost:3000,可通过BASE_URL环境变量覆盖。
默认压测速率是针对本地限流参数ADMISSION_GATE_MAX_INFLIGHT=500调校的。该准入阀(admission gate)会限制每个 Pod的在途(in-flight)请求总数。
补充:底层实现准入阀的源码位于 apps/sim/lib/core/admission/gate.ts。它是一个纯进程内(in-process)原子计数器:
MAX_INFLIGHT通过Number.parseInt(env.ADMISSION_GATE_MAX_INFLIGHT ?? '') || 500解析,默认值为 500。每个 Pod 维护自己的计数器,因此 N 个 Pod 的聚合上限是N × MAX_INFLIGHT——源码注释明确建议“按每个 Pod 能承受的量来配置ADMISSION_GATE_MAX_INFLIGHT”。 在 apps/sim/app/api/workflows/[id]/execute/route.ts 中,POST处理器会先调用tryAdmit()获取 Admission Ticket,拿不到则直接返回admissionRejectedResponse()(即 429);拿到后在finally中调用ticket.release()归还名额。会话型请求(带 cookie)不经过准入阀,而 API Key / 公开 API / 内部 JWT 调用都会受其约束。
关于 429 响应:可安全重试的准入失败
当请求被准入阀拒绝时,服务端返回的 429 响应体与Retry-After头由 apps/sim/lib/core/admission/transient-failure.ts 定义:
| 失败类别 | 状态码 | code | 是否可自动重试 | Retry-After |
|---|---|---|---|---|
| 准入阀容量(GATE_CAPACITY) | 429 | ADMISSION_GATE_CAPACITY | 是 | 5 秒 |
| 计费方并发(RESERVATION_CONCURRENCY) | 429 | EXECUTION_CONCURRENCY_LIMIT | 是 | 5 秒 |
| 计费方余量不足(PAYER_HEADROOM) | 402 | EXECUTION_PAYER_HEADROOM_EXHAUSTED | 否 | — |
| 成员余量不足(MEMBER_HEADROOM) | 402 | EXECUTION_MEMBER_HEADROOM_EXHAUSTED | 否 | — |
| 基础设施过载(INFRASTRUCTURE) | 503 | SERVICE_OVERLOADED | 是 | 5 秒 |
classifyTransientAdmissionFailure()只把retryable === true且 code 匹配的失败识别为“可安全重试的瞬态准入失败”,这对理解压测中出现的 429/503 含义很有帮助:429 通常意味着“再等等(约 5 秒)重试即可”,而 402 表示余量类硬性拒绝,不应盲目重试。
场景一:基线并发(Baseline Concurrency)
该场景用于向单个工作流逐步加压,观察正常的排队(queueing)行为。
默认施压曲线:
- 起始
2请求/秒 - 爬坡至
8请求/秒 - 以
8请求/秒保持20秒 - 该曲线适合用于验证针对Free 工作空间并发数为 5的排队表现
运行命令:
WORKFLOW_ID=<workflow-id> \ SIM_API_KEY=<api-key> \ bun run load:workflow:baseline可选环境变量(均带默认值,见 apps/sim/package.json):
| 变量 | 默认值 | 说明 |
|---|---|---|
BASE_URL | http://localhost:3000 | 压测目标地址 |
WARMUP_DURATION | 10 | 爬坡阶段时长(秒) |
WARMUP_RATE | 2 | 爬坡起始速率(请求/秒) |
PEAK_RATE | 8 | 峰值速率(请求/秒) |
HOLD_DURATION | 20 | 峰值保持时长(秒) |
更高套餐工作空间的本地起点:
- Pro:
PEAK_RATE=20到40 - Team 或 Enterprise:
PEAK_RATE=50到100
YAML 结构解析:场景配置位于 apps/sim/scripts/load/workflow-concurrency.yml。它定义了两个 phase:baseline-ramp(duration=WARMUP_DURATION、arrivalRate=WARMUP_RATE、rampTo=PEAK_RATE)和baseline-hold(duration=HOLD_DURATION、arrivalRate=PEAK_RATE)。请求体通过{{ $processEnvironment.WORKFLOW_ID }}、{{ $processEnvironment.SIM_API_KEY }}注入环境变量,runId使用 Artillery 内建的{{ $uuid }}保证每次请求唯一。默认请求头包含content-type: application/json、x-api-key与x-execution-mode: async。
场景二:排队冲击波(Queueing Waves)
该场景用于向同一工作空间中的单个工作流反复发送突发流量,检验排队与吞吐的承受能力。
默认施压曲线:
| 阶段 | 速率 | 时长 |
|---|---|---|
| Wave 1 | 6请求/秒 | 10秒 |
| 静默间隔 | 1请求/秒 | 5秒 |
| Wave 2 | 8请求/秒 | 15秒 |
| 静默间隔 | 1请求/秒 | 5秒 |
| Wave 3 | 10请求/秒 | 20秒 |
运行命令:
WORKFLOW_ID=<workflow-id> \ SIM_API_KEY=<api-key> \ bun run load:workflow:waves可选环境变量(见 apps/sim/package.json):
| 变量 | 默认值 | 说明 |
|---|---|---|
BASE_URL | http://localhost:3000 | 压测目标地址 |
WAVE_ONE_DURATION | 10 | 第一波时长(秒) |
WAVE_ONE_RATE | 6 | 第一波速率(请求/秒) |
QUIET_DURATION | 5 | 两波之间的静默时长(秒) |
WAVE_TWO_DURATION | 15 | 第二波时长(秒) |
WAVE_TWO_RATE | 8 | 第二波速率(请求/秒) |
WAVE_THREE_DURATION | 20 | 第三波时长(秒) |
WAVE_THREE_RATE | 10 | 第三波速率(请求/秒) |
YAML 结构解析:apps/sim/scripts/load/workflow-waves.yml 定义了 5 个 phase:wave-one、quiet-gap、wave-two、quiet-gap-two、wave-three。其中静默阶段用arrivalRate: 1保持极低流量而非完全归零,便于观察队列在低负载窗口的消化能力。请求体除source与runId外,还携带了waveProfile: single-workspace标记,便于在服务端日志中区分不同压测场景的请求来源。
场景三:双工作空间隔离(Two-Workspace Isolation)
该场景用于同时向来自不同工作空间的两个工作流发送混合流量,对比观察:一个工作空间承受队列压力时,是否会对另一个工作空间产生可见影响。
默认施压曲线:
- 总速率:
9请求/秒,持续30秒 - 权重分配:
8 : 1 - 实际效果:工作空间 A 承受重压,同时工作空间 B 仍保持轻量流量
运行命令:
WORKFLOW_ID_A=<workspace-a-workflow-id> \ SIM_API_KEY_A=<workspace-a-api-key> \ WORKFLOW_ID_B=<workspace-b-workflow-id> \ SIM_API_KEY_B=<workspace-b-api-key> \ bun run load:workflow:isolation注意:该场景需要两组独立的工作流 ID 与 API Key,分别对应工作空间 A 与 B。
可选环境变量(见 apps/sim/package.json):
| 变量 | 默认值 | 说明 |
|---|---|---|
BASE_URL | http://localhost:3000 | 压测目标地址 |
ISOLATION_DURATION | 30 | 混合施压时长(秒) |
TOTAL_RATE | 9 | 总请求速率(请求/秒) |
WORKSPACE_A_WEIGHT | 8 | 工作空间 A 的流量权重 |
WORKSPACE_B_WEIGHT | 1 | 工作空间 B 的流量权重 |
YAML 结构解析:apps/sim/scripts/load/workflow-isolation.yml 定义了两个带weight的场景:workspace-a-traffic(默认权重 8)与workspace-b-traffic(默认权重 1),Artillery 会按权重比例分配TOTAL_RATE的流量。两个场景各自通过独立的WORKFLOW_ID_A/SIM_API_KEY_A与WORKFLOW_ID_B/SIM_API_KEY_B环境变量注入目标与鉴权头,并在请求体中以workspace: a/workspace: b标记来源。x-execution-mode: async位于config.defaults.headers,两个场景共用。
压测输出解读与调优建议
Artillery 输出会展示请求计数与响应码分布,对于本地快速验证通常已经足够。README 给出了两条核心判读经验:
- 看到 429 是预期行为:在默认参数下,当在途请求接近
ADMISSION_GATE_MAX_INFLIGHT=500时,你会看到 429 响应。这正是准入阀按预期工作的信号——它把超过容量的请求挡在门外并让调用方稍后重试。 - 429 或 ETIMEDOUT 过多时先降速:如果本地压测出现大量
429或ETIMEDOUT,应先把速率调低,再考虑延长持续时间,而不是继续加大压力。这是一种稳健的“先验证正确性、再验证容量”的思路。
从源码角度看,这个建议与准入阀的进程内计数器设计一致:tryAdmit()在inflight >= MAX_INFLIGHT时直接返回null,路由随即返回 429(apps/sim/app/api/workflows/[id]/execute/route.ts)。本地开发机资源有限时,降低PEAK_RATE等速率参数比单纯延长HOLD_DURATION更能稳定复现排队行为。
附:场景速查表
| 场景 | 命令别名 | 目标 | 默认速率 | 典型观察点 |
|---|---|---|---|---|
| 基线并发 | load:workflow:baseline(load:workflow为其别名) | 单工作流 | 2 → 8 req/s,保持 20s | 正常排队行为、Free 并发 5 下的表现 |
| 排队冲击波 | load:workflow:waves | 单工作流(同工作空间) | 6 / 8 / 10 req/s 三波 | 突发流量下的队列消化能力 |
| 双工作空间隔离 | load:workflow:isolation | 两个工作空间的工作流 | 9 req/s,权重 8:1 | 工作空间间的队列压力隔离 |
三个场景的公共行为:全部发送x-execution-mode: async请求头;均通过bun run <script>调用 apps/sim/package.json 中定义的脚本,底层由 Artillery 2.0.34 执行位于 apps/sim/scripts/load/ 的 YAML 场景文件;$processEnvironment机制让所有可调参数都以环境变量形式注入,无需修改任何配置文件即可完成多轮不同强度的压测。
【免费下载链接】simSim is the collaborative workspace to build, deploy, and monitor AI agents and workflows. Used by 100,000+ builders.项目地址: https://gitcode.com/GitHub_Trending/sim16/sim
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考