Windmill 吞吐量基准测试指南:用 Deno/TS 套件测量 Job 与 Flow 执行性能

发布时间:2026/9/13 18:48:53
Windmill 吞吐量基准测试指南:用 Deno/TS 套件测量 Job 与 Flow 执行性能 Windmill 吞吐量基准测试指南用 Deno/TS 套件测量 Job 与 Flow 执行性能【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmillWindmill 开源仓库自带一套基于 Deno/TypeScript 的基准测试Benchmark套件用于量化 Windmill 作业调度与工作流执行的吞吐量。本文以 benchmarks/README.md 为核心结合 benchmark_oneoff.ts、benchmark_suite.ts、lib.ts 等源码实现系统讲解基准测试的三种运行模式单测、套件、交互工具、全部内置 Benchmark Kind、套件配置结构、结果落盘与 SVG 图形生成以及持续集成中自动跑基准的完整工作流。读完本文你将能在自己的 Windmill 实例上复现官方基准、定制自己的压测场景并读懂底层测量逻辑。基准测试套件概览benchmarks/目录是一组可直接运行的 Deno 脚本核心目标只有一个测量 Windmill 每秒能执行多少个 Job 或 Flow。套件依赖公开的 Windmill TS SDKhttps://deno.land/x/windmillv1.174.0/mod.ts通过 API 向目标实例批量提交作业、轮询完成数量最终算出吞吐率。目录内主要文件职责如下文件作用benchmark_oneoff.ts单次基准测试入口批量建任务、轮询进度、计算并打印吞吐量benchmark_suite.ts按 JSON 配置顺序执行一组基准先预热warm up结果追加写入*_benchmark.jsonmain.ts交互式基准工具按时间窗口持续发压支持多 Worker 并发与指标导出worker.tsmain.ts的压测子进程Deno Worker每个 Worker 以恒定速率向队列灌入作业scraper.ts从 Prometheus 指标端点拉取直方图/计数器数据lib.ts共享工具登录、创建基准脚本、WAC 脚本模板、Flow 负载生成graph.tsSVG 绘图逻辑drawGraph/drawGraphMultibenchmark_graphs.ts依据graphs_config.json从 JSON 数据生成 SVG 趋势图action.ts自定义压测动作的定义与求值快速开始1. 安装 Deno套件是纯 Deno 脚本唯一前置依赖是 Deno 运行时官方 CI 使用 Deno v2.x见 .github/workflows/benchmark.ymlcurl -fsSL https://deno.land/install.sh | sh2. 运行单个基准deno run -A benchmark_oneoff.ts --kind noop --jobs 10000这条命令会向默认地址http://127.0.0.1:8000本地启动的 Windmill 实例批量提交 10000 个 noop空操作作业然后轮询队列直至全部完成输出平均吞吐量。noop任务不执行任何实际逻辑专门用来测量纯调度开销。3. 运行完整套件deno run -A benchmark_suite.ts -c suite_config.jsonbenchmark_suite.ts会先执行一次 50000 个 noop 作业的预热可通过--no-warm-up跳过再依次执行配置文件中列出的所有基准每次结果追加到kind_benchmark.json多 Worker 时文件名为kind_nworkers_benchmark.json便于积累历史数据绘制趋势图。4. 运行 WAC v2 对比基准deno run -A benchmark_suite.ts -c suite_wac.jsonWACWorkflow-as-Code工作流即代码是 Windmill 用普通代码表达工作流的方式。suite_wac.json将 WAC 脚本与等价结构的传统 Flow 放在一起压测直接对比两种工作流编排方式的吞吐差异。Benchmark Kind 全解析脚本类Script benchmarksKind说明脚本内容见 lib.ts 的createBenchScriptnoop空作业测量纯调度开销无脚本直接以{kind: noop}批量入队denoDeno 运行时脚本export function main(){ return Deno.env.get(WM_JOB_ID); }bunBun 运行时脚本export function main(){ return Bun.env[WM_JOB_ID]; }pythonPython 3 脚本def main(): return os.environ.get(WM_JOB_ID)goGo 脚本func main() (string, error) { return os.Getenv(WM_JOB_ID), nil }bashBash 脚本echo $WM_JOB_IDnativetsBunNative无沙箱隔离的本地 TS//native注释标记返回BASE_URL /api/version的文本dedicated专用 Worker 模式bun接收参数uuid并原样返回dedicated_nativets专用 Worker NativeTS//native标记返回常量 42每个语言脚本都通过ScriptService.createScript部署到f/benchmarks/kind路径并等待部署完成waitForDeployment轮询getScriptDeploymentStatus最多 20 次、每次间隔 0.5 秒。dedicated系列还会额外调用runWaitResultScriptByPath等待专用 Worker 就绪。值得注意的是所有脚本都返回WM_JOB_ID环境变量——这既是校验作业正确性的手段后面会讲verifyOutputs也避免了脚本内引入随机延迟。Flow 类Flow benchmarksKind说明2steps2 步 Flowdeno 脚本 identity 步骤见getFlowPayload默认分支bigscriptinflow包含约 100 行重复注释膨胀的大型 raw bash 脚本的 Flowflow_seq_2_bun2 个顺序执行的 bun 步骤flow_par_2_bun2 个并行 bun 步骤branchallparallel: trueflow_seq_3_bun3 个顺序执行的 bun 步骤flow:path按路径加载工作区中自定义 Flow并递归统计其总步骤数含子 Flowscript:path按路径执行自定义脚本Flow 基准以{kind: flow, flow_value: ...}的负载提交。从 benchmark_oneoff.ts 的代码可以看到2steps与bigscriptinflow直接使用getFlowPayload(kind)生成的 Flow 定义入队而flow:xxx会先通过getFlowStepCount递归解析 Flow 的模块树统计出包含子 Flow 在内的总步骤数。吞吐量换算Flow 基准在计算吞吐时会把已完成作业数除以(步骤数 1)因为每个 Flow 实例会拆成 N 个子作业 1 个父作业completedJobs Math.floor(completedJobs / (nStepsFlow 1))这样才能得到每秒完成的 Flow 数而非每秒完成的步骤数。WAC v2 类workflow-as-codeWAC 基准脚本由 lib.ts 中的WAC_SCRIPTS表定义全部以 bun 语言部署到f/benchmarks/kind// wac_seq_22 个顺序 task import { task, workflow } from windmill-client; const step_a task(async () { return 1; }); const step_b task(async () { return 2; }); export const main workflow(async () { const a await step_a(); const b await step_b(); return { a, b }; }); // wac_par_22 个并行 taskPromise.all import { task, workflow } from windmill-client; const step_a task(async () { return 1; }); const step_b task(async () { return 2; }); export const main workflow(async () { const [a, b] await Promise.all([step_a(), step_b()]); return { a, b }; });Kind说明wac_seq_22 个顺序 task每个 task 产生一个子作业wac_par_22 个并行 taskPromise.allwac_seq_33 个顺序 taskwac_inline_22 个 inline stepstep(a, () 1)不产生子作业其中STEPS_PER_WORKFLOW表lib.ts记录了每种 Kind 的子作业数task()会为每一步创建子作业而step()完全内联在当前进程中。因此wac_inline_2的nStepsFlow为 0吞吐计算时不会被除法折算——这正是 inline step 能显著降低编排开销的关键。套件配置文件详解主套件 suite_config.json[ { kind: noop, jobs: 90000 }, { kind: 2steps, jobs: 250 }, { kind: deno, jobs: 500 }, { kind: bun, jobs: 500 }, { kind: python, jobs: 500 }, { kind: go, jobs: 2000 }, { kind: bash, jobs: 2000 }, { kind: nativets, jobs: 2000 }, { kind: bigrawscript, jobs: 4000 }, { kind: bigscriptinflow, jobs: 4000 } ]配置是{ kind, jobs, noSave? }的数组kind指定基准类型jobs指定提交数量noSave: true表示跑完不写入结果文件。可以看到 noop 压力最大90000因为空作业执行最快语言类基准的作业数则与该语言单作业开销相匹配。专用套件 suite_dedicated.json[ { kind: dedicated, jobs: 50000, noSave: true }, { kind: dedicated, jobs: 90000 } ]第一轮不保存结果相当于专用 Worker 模式的预热第二轮正式记录数据。WAC 对比套件 suite_wac.json[ { kind: wac_seq_2, jobs: 250 }, { kind: wac_par_2, jobs: 250 }, { kind: wac_seq_3, jobs: 200 }, { kind: wac_inline_2, jobs: 500 }, { kind: flow_seq_2_bun, jobs: 250 }, { kind: flow_par_2_bun, jobs: 250 }, { kind: flow_seq_3_bun, jobs: 200 } ]前三项是 WAC 的 task 编排后三项是对应结构的传统 Flowbun 实现wac_inline_2则单独展示 inline step 的极限吞吐。命令行参数与认证方式benchmark_oneoff.ts与benchmark_suite.ts共用一套参数基于 cliffy CLI 框架并支持环境变量注入参数环境变量默认值说明--host url—http://127.0.0.1:8000被测 Windmill 实例地址-e --email—adminwindmill.dev登录邮箱-p --password—changeme登录密码-t --tokenWM_TOKEN—API Token优先于邮箱密码登录-w --workspaceWM_WORKSPACEadmins提交作业的工作区--kind kind—必填oneoff基准类型-j --jobs n—10000提交的作业数--no-verify—false跳过结果校验-c --config-path—必填suite套件 JSON 配置路径支持 http 远程 URL--no-warm-up—false跳过 50000 noop 预热--workers n—1参与基准的 Worker 数仅影响结果文件名与图标题--factor n—1将每个基准的作业数乘以该系数从 benchmark_oneoff.ts 的 CLI 定义看WM_TOKEN与WM_WORKSPACE通过.env()注入且 token 优先于账号密码if (!token) { ... } else { final_token token; }。CI 中依赖 license 的 EE 实例与本地社区版实例均可作为被测目标。测量原理提交、轮询与校验以 benchmark_oneoff.ts 为例一次基准的完整生命周期如下1. 准备脚本若 kind 属于语言类或 WAC 类先通过 SDK 创建/覆盖f/benchmarks/kind脚本并等待部署dedicated系列还等待专用 Worker 上线。2. 批量提交向POST /api/w/workspace/jobs/add_batch_jobs/count一次性提交jobs个作业noop 负载为{kind:noop}脚本负载为{kind:script,path:f/benchmarks/kind}Flow 负载为{kind:flow,flow_value:...}。请求返回所有作业 UUID记录批量创建耗时。3. 轮询进度基准计时从队列中待执行数开始下降时启动。循环读取GET /api/w/workspace/jobs/completed/count?tags...与/jobs/queue/count实时打印elapsed | jobs executed (thr: inst - avg) | remaining。这里使用了NON_TEST_TAGS[deno,python,go,bash,dedicated,bun,nativets,dedicated_nativets,flow]过滤掉其他并发作业的干扰。为避免异常挂起轮询设置了 10 分钟超时POLL_TIMEOUT_MS。4. 输出吞吐全部完成后打印jobs、duration、avg. throughput (jobs/time)并返回{ throughput }供套件收集。5. 结果校验默认--no-verify未开启会对每个作业 UUID 调用JobService.getCompletedJob检查job.success为真且job.result uuid即脚本正确输出了自己的WM_JOB_ID统计Incorrect results。校验会排除 noop、nativets、自定义 flow/script 等无法简单比对输出的类型。交互式基准工具 main.ts当需要持续 N 秒恒速发压或限制每秒最大吞吐时使用交互式工具deno run -A main.ts -e adminwindmill.dev -p changeme --host http://localhost:8000完整选项选项默认值说明--workers n1并发压测子进程数-s --seconds n30压测持续秒数--max n—每个 Worker 最大操作数上限--maximum-throughput nInfinity每秒最多启动的作业/Flow 数按 Worker 均分--use-flowsfalse压 Flow 而非单作业--flow-pattern p2stepsFlow 模板2steps、onebranch--script-pattern pdeno脚本模板deno、python、go、bash、dedicated、bun--custom path—从 JSON 文件加载自定义 Action见 action.ts--zombie-timeout ms90000等待作业完成的最长时间-c --continuousfalse无限期运行禁用指标采集与导出-m --metrics urlhttp://localhost:8001/metricsPrometheus 指标端点--export-json file—导出均值/标准差到 JSON--export-csv file—导出原始采样到 CSV--export-histograms names—导出为直方图的指标名--export-simple names—导出为简单值的指标名--histogram-buckets bucketsInf,10,5,...直方图桶定义运行流程见 main.ts先拉取/api/version打印后端版本再按per_worker_throughput maximumThroughput / num_workers把总吞吐目标均摊给每个 Worker每个 Worker 以固定速率循环调用add_batch_jobs并追踪未完成作业主进程每 100ms 刷新队列长度与实时吞吐压测结束后等待所有僵尸作业被消费最终把吞吐按jobs / (seconds time_to_shutdown)折算。若指定了--export-json/--export-csv会启动 scraper.ts Worker 从指标端点采集数据并落盘。结果持久化与 SVG 图形生成结果文件套件模式每完成一个基准就把{ value: throughput, ts: Date.now() }追加到kind_benchmark.json多 Worker 为kind_nworkers_benchmark.json。值得注意benchmark_suite.ts在追加前会尝试从远端benchmarks分支拉取已有的同名 JSON见 benchmark_suite.ts实现跨版本积累历史数据拉取失败则新建文件。这样每个 JSON 都是一条吞吐量的时间序列。生成趋势图deno run -A benchmark_graphs.ts -c graphs_config.jsonbenchmark_graphs.ts 读取配置中声明的基准组合从本地kind_benchmark.json含_nworkers变体读取最近 10 个数据点用 graph.ts 的drawGraph单序列或drawGraphMulti多序列对比绘制 SVG文件名取自graph_title的空格替换为下划线。graphs_config.json 预置了十余张图例如noop throughput benchmark1/4/8 Worker 的 noop 吞吐对比go vs python vs deno vs bun vs bash vs nativets单 Worker 下六种语言运行时横向对比bun vs dedicated vs noop专用 Worker 与常规调度的开销差距WAC v2 sequential vs flow sequential (2 steps, bun)WAC 与 Flow 的顺序编排对比WAC v2 parallel vs flow parallel (2 steps, bun)并行编排对比WAC v2 patterns comparisonWAC 四种模式顺序/并行/3 步/inline互相比较CI 自动化每小时自动跑基准.github/workflows/benchmark.yml 定义了完整的自动化流程通过 cron0 0 */1 * *每小时触发共 6 个 JobJob拓扑说明benchmark_single1 个 Windmill 容器内含 worker Postgres运行suite_config.jsonbenchmark_dedicated1 个容器WORKER_GROUPdedicated、DEDICATED_WORKERadmins:f/benchmarks/dedicated运行suite_dedicated.json跳过预热benchmark_4workers1 个主容器 3 个MODEworker容器suite_config.json --workers 4 --factor 3benchmark_8workers1 个主容器 7 个 worker 容器suite_config.json --workers 8 --factor 3benchmark_wac1 个容器运行suite_wac.jsonbenchmark_graphs依赖上述 5 个 Job检出benchmarks分支、合并下载结果、生成 SVG 并提交推送CI 环境的几个关键配置实例镜像为ghcr.io/windmill-labs/windmill-ee:mainPostgres 调优参数shared_buffers2GB、work_mem32MB、effective_cache_size4GB主 worker 标签为deno,bun,go,python3,bash,dependency,flow,nativets4/8 Worker 场景通过--factor 3把作业数放大三倍以匹配更强的处理能力。生成的*_benchmark.json与 SVG 图最终提交到benchmarks分支形成持续的吞吐量监控曲线。实践建议与注意事项先本地起实例再压测默认 host 是http://127.0.0.1:8000本地可用docker-compose.yml或start-dev-db.sh启动开发实例后直接开跑。善用 noop 建立基线noop 反映纯调度与队列开销是判断任何性能回归的基准线语言类基准的差距则应归因于运行时启动与隔离成本。预热不可省benchmark_suite.ts默认先跑 50000 个 noop 预热避免冷启动依赖缓存、JIT、连接池污染数据专用 Worker 套件的第一轮noSave也是同样的目的。区分作业吞吐与Flow 吞吐Flow/WAC 结果经过nStepsFlow 1折算阅读*_benchmark.json时注意单位是每秒 Flow 数。控制变量批量提交阶段不计入吞吐计时计时从队列开始消化起算结果校验阶段不计入吞吐如需极速复测可加--no-verify。多 Worker 结果命名--workers nn1会把结果写入_nworkers后缀文件与单 Worker 数据隔离绘图时需在graphs_config.json中显式声明对应workers。通过这套工具你既能用一条命令复现官方每小时自动跑的通量基准也能借助flow:path、script:path、--custom把真实业务脚本纳入压测让 Windmill 的性能表现始终处于可量化、可追踪的状态。【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考