Convex Backend 压测指南:使用 LoadGenerator 对自托管 Convex 实例进行基准测试
2026/9/24 9:37:24 网站建设 项目流程
  • 数据库
  • 后端

【免费下载链接】convex-backend

The open-source reactive database for app developers

项目地址:https://gitcode.com/gh_mirrors/co/convex-backend
点击查看免费下载

导读

本文基于 self-hosted/advanced/benchmarking.md 及仓库中开源的压测工具 LoadGenerator(位于 crates/load_generator)编写,完整讲解如何对自托管(self-hosted)的 Convex Backend 实例执行负载测试与性能基准测试。读完本文,你将掌握:LoadGenerator 的整体架构与工作流程、面向自托管实例的两步压测流程(部署 ScenarioRunner 函数 + 运行 LoadGenerator)、各类内置 workload 配置的字段含义,以及如何编写自定义压测场景与自定义 Convex 函数,从而量化评估自托管实例的函数延迟、吞吐量与整体稳定性。

注意:LoadGenerator 是专用于 Convex 生态的压测工具,若你的目标是更通用的 HTTP 层压测,可结合本文思路自行扩展;本文聚焦仓库中已验证的官方流程。


一、LoadGenerator 是什么

LoadGenerator 是 Convex 开源仓库中自带的压测与基准测试工具,定位是"评估 Convex 在不同负载模式下的性能表现"。根据 crates/load_generator/README.md,它可以测量三方面核心指标:

  • 函数延迟(Function latency):query / mutation / action / HTTP action 等请求的响应时延;
  • 吞吐量(Throughput):在给定速率(每秒请求数)或并发线程数下,后端能承受的处理能力;
  • 整体稳定性(Overall system stability):长时间高负载下,系统是否出现错误率飙升、内存泄漏或功能异常。

工作流程

LoadGenerator 的完整工作链路(编号遵循原文档)如下:

  1. Provisioning(实例准备):自动创建(provision)一个 Convex 实例,或直接指向一个已存在的实例;
  2. 下发场景(Sending scenarios):将预定义或自定义的压测场景发送给 ScenarioRunner;
  3. 收集指标(Collecting metrics):从已执行的场景中收集性能指标(函数执行耗时、事件等);
  4. 生成统计报告(Generating reports):生成包含延迟指标(p50 / p95 / p99 等)的详细统计报告;
  5. 可选:上报监控系统:将指标发送到生产监控系统(如 Datadog),实现长期观测。

架构图

原文档给出了如下的组件协作关系,LoadGenerator 是中枢:它向 ScenarioRunner 发送压测场景,ScenarioRunner 再以 query / mutation 的形式访问 Backend(被测的 Convex 后端);反向地,ScenarioRunner 把执行产生的事件(Events)回传给 LoadGenerator,由其生成 Stats Report;同时 LoadGenerator 的指标可被 Metrics Collector(如 Datadog、Prometheus)采集。

┌──────────┐ │ Stats │ │ Report │ ┌────────────────┐ ┌───────────────────┐ ┌───────────────┐ └──────────┘ │ │ │ │ queries, │ │ ▲ │ │ Scenarios │ │ mutations │ │ └─────────┬───│ LoadGenerator │──────────▶│ ScenarioRunner │──────────▶│ Backend │ ┌──────────────┐ │ │ │◀──────────│ │◀──────────│ │ │ │ │ │ │ Events │ │ │ │ │ Metrics │ │ └────────────────┘ └───────────────────┘ └───────────────┘ │ Collector │◀─┘ │(e.g. Datadog)│ │ │ └──────────────┘

从源码实现看,这一架构在 crates/load_generator/src/main.rs 中有明确对应:run_workload函数会以node dist/scenario-runner.js --deployment-url <backend_url> --admin-key <admin_key> --load-generator-port <port> --scenarios <json>的方式直接 spawn 一个 ScenarioRunner 子进程(注意源码注释说明:必须直接 spawnnode,而不能用npm start,否则子进程无法从父进程被可靠 kill,参见 npm issue #4603);LoadGenerator 自身则通过 axum 启动一个 HTTP/WebSocket 服务(/sync路由),接收 ScenarioRunner 推送回来的事件,事件经EventProcessor汇总到Stats,在压测时长结束后生成统计报告。


二、快速开始:运行 LoadGenerator

查看帮助

在仓库根目录(convex目录)下执行:

cargo run -p load_generator --bin load-generator -- --help

即可看到全部命令行参数说明。若需要 tracing 日志,在命令前加上环境变量:

RUST_LOG=info cargo run -p load_generator --bin load-generator -- --help

预配置的工作负载

仓库的Justfile(crates/load_generator/Justfile)预置了多套运行方式,核心差异在 provisioner(实例供给方):

  • self-hosted:面向自托管后端(本文重点,见下一节);
  • dev/dev-quick/dev-conductor:面向本地开发环境,绕过 Big Brain 直接连本地进程;
  • dev-bb:连本地 Big Brain;
  • prod:连生产 Big Brain,需要设置CONVEX_OVERRIDE_ACCESS_TOKEN环境变量(来自 1Password 的密钥)。

所有预置 workload 命令都带有--stats-report --once --duration 60dev-quick为 10 秒),即运行 60 秒、打印统计报告后退出一次。例如:

just dev light

等价于(在仓库根目录):

cargo run --release -p load_generator --bin load-generator \ -- crates/load_generator/workloads/light.json --duration 60 \ --provisioner open-source-release --stats-report --once

主要命令行参数

结合 crates/load_generator/src/main.rs 中Config结构体的 clap 定义,常用参数如下:

参数说明默认值
--workload <path>(位置参数)workload 配置文件路径,运行时解析为Workload结构必填
--duration <secs>LoadGenerator 运行秒数,超时后关闭连接、结束场景必填
--stats-report结束后打印统计报告(含延迟分位数)关闭
--once只运行一轮 workload 后退出;不加则循环运行关闭
--interface/--portHTTP/WebSocket 服务绑定的网卡与端口0.0.0.0/8010
--metrics-addrPrometheus 指标导出地址(如0.0.0.0:9100
--provisioner <name>实例供给方(open-source-release等),与--existing-instance-url互斥二选一必填
--existing-instance-url指向已存在实例(自托管场景使用),需配合 admin key
--existing-instance-admin-key已存在实例的 admin key
--existing-project-slug复用已存在项目(配合 provisioner 使用)
--skip-build跳过 ScenarioRunner 的构建(turbo build)关闭
--skip-actions-deploy跳过部署 node actions(避免在生产创建过多 AWS Lambda)关闭
--use-preview-deployments预览部署压测模式(配合--num-preview-deployments--num-preview-deployment-pushes关闭

三、对自托管 Convex 进行压测(核心流程)

原文档给出的自托管压测流程分两步,务必按顺序执行。

第 1 步:将 ScenarioRunner 函数推送到自托管后端

cd npm-packages/scenario-runner npx convex deploy --admin-key=<your-admin-key> --url=<your-backend-url>

强烈警告(原文档原文强调):不要对生产实例执行此操作!这一步会替换掉你的函数deploy会整体覆盖该项目的函数代码)。请使用仅用于测试的独立 Convex 后端。

第 2 步:针对自托管后端运行 LoadGenerator

cd ../../crates/load_generator just self-hosted crates/load_generator/workloads/<your-workload>.json \ --existing-instance-url <your-backend-url> \ --existing-instance-admin-key <your-admin-key>

just self-hosted展开后的完整命令为(来自 Justfile):

cargo run --release -p load_generator --bin load-generator \ -- --stats-report --once --duration 60 \ crates/load_generator/workloads/<your-workload>.json \ --existing-instance-url <your-backend-url> \ --existing-instance-admin-key <your-admin-key>

即:以 release 模式构建运行,持续 60 秒,结束后输出统计报告。从 main.rs 看,当同时提供--existing-instance-url--existing-instance-admin-key时,会走run_workload(None, backend_url, admin_key, ...)分支,直接对指定实例施压;否则走 provisioner 自动供给分支(生产供给还会加入最长 30 秒的随机 jitter 避免多实例同时抢占)。

关于 rate 与线程两种模式(详见 main.rs 的Mode枚举):

  • rate(每秒请求数):以固定速率发送请求,如 workloads/prod.json;
  • benchmark(线程数):以指定数量的线程连续发请求,每个线程串行等待上一个请求响应后才发下一个,用于测量后端在最大并发下的极限能力,如 workloads/benchmark_query.json。

运行期间的内部行为

压测启动后,LoadGenerator 会依次执行(对应 main.rs 的run_workload):

  1. 调用wait_for_http_health等待后端 HTTP 健康检查通过(最多重试 2 次、每次间隔 250ms),并读取backend_version作为指标标签;
  2. 执行setup,按 workload 中的num_rows(默认 500)与num_vector_rows(默认 0)向后端写入初始数据;
  3. 构建并 spawn ScenarioRunner 子进程,传入部署 URL、admin key、load-generator 端口与场景 JSON;
  4. LoadGenerator 启动 HTTP/WebSocket 服务,在--duration指定的时长内持续接收事件;
  5. 时长结束后向所有 WebSocket 连接发送 Close,kill 掉 ScenarioRunner 子进程,再等待 10 秒让后端处理完剩余日志事件;
  6. 若指定--stats-report则打印统计报告;随后调用fail_if_too_many_errors()——如果错误过多,进程以非零状态退出,方便 CI 判断压测是否通过。

四、workload 配置文件详解

workload 是 JSON 文件,结构定义在 main.rs:

struct Workload { name: String, scenarios: Vec<ScenarioConfig>, num_vector_rows: u64, // 初始 setup mutation 写入的向量行数 num_rows: u64, // 初始 setup mutation 写入的消息行数,默认 500 }

顶层字段:

字段说明
nameworkload 名称,会作为指标标签load_description(格式为{name}_{duration}s
scenarios场景数组,每个场景含name、场景专有参数、以及ratebenchmark模式
num_vector_rows初始化时写入的向量搜索行数(prod.json中为 200)
num_rows初始化时写入的消息行数,默认 500

内置场景类型

Scenario枚举(main.rs)支持以下场景,覆盖了从普通函数到订阅、搜索、向量搜索、快照导出、HTTP action 的完整能力面:

场景name字段说明
RunFunctionpath(模块:函数名)、fn_typequery/mutation/action按路径调用 ScenarioRunner 中的 Convex 函数,是最通用的场景
ObserveInsertsearch_indexes(bool)建立订阅观察插入事件,可选是否涉及搜索索引
Search执行全文搜索压测
VectorSearch执行向量搜索压测
SnapshotExport触发快照导出压测
CloudBackup触发云备份流程压测(prod.json中 rate 低至 0.00005)
ManyIntersectionsnum_subscriptions同时建立大量订阅并产生交叉失效(用于压测订阅失效路径)
HoldSubscriptionsnum_subscriptionshold_duration_secsinvalidation_interval_secs(可选)、num_invalidations(可选)长时间持有订阅并按间隔触发失效
RunHttpActionpathmethod通过 HTTP 调用 action(如POST

示例 1:prod.json(混合负载,模拟生产流量)

workloads/prod.json 是仓库中最全面的混合负载示例,模拟了生产环境常见的操作组合:带搜索的查询与写入、组件(components)的 query/mutation、搜索索引观察、全文搜索、向量搜索、定时任务(schedule)、HTTP action、快照导出与云备份。片段如下:

{ "name": "prod", "scenarios": [ { "name": "RunFunction", "path": "query_index:queryMessagesWithSearch", "fn_type": "query", "rate": 10 }, { "name": "RunFunction", "path": "update", "fn_type": "mutation", "rate": 2 }, { "name": "ObserveInsert", "search_indexes": true, "rate": 5 }, { "name": "Search", "rate": 6 }, { "name": "VectorSearch", "rate": 5 }, { "name": "RunHttpAction", "path": "streaming", "method": "POST", "rate": 2 }, { "name": "SnapshotExport", "rate": 0.0005 }, { "name": "CloudBackup", "rate": 0.00005 } ], "num_vector_rows": 200 }

注意prod.jsonSnapshotExport的 rate 为 0.0005(即每 2000 秒一次)、CloudBackup为 0.00005(每 20000 秒一次),这类低频后台任务场景主要是为了模拟真实生产环境中的偶发重操作。

示例 2:benchmark_query.json(线程模式,测极限吞吐)

workloads/benchmark_query.json 展示了 benchmark 模式——用benchmark字段替代rate

{ "name": "benchmark_query", "scenarios": [ { "name": "RunFunction", "path": "query_index:queryMessagesWithSearch", "fn_type": "query", "benchmark": 80 } ] }

含义:启动 80 个线程,每个线程串行地持续发起queryMessagesWithSearch查询,测量后端的极限并发吞吐与延迟。

其他内置 workload

仓库 crates/load_generator/workloads 目录下还提供了针对不同目的的配置,可根据压测目标选用:

  • light.json:轻量混合负载(含 action、搜索、云备份),适合快速冒烟测试;
  • heavy.json/large.json:高负载 / 大数据量压测;
  • benchmark_insert.jsonbenchmark_search.jsonbenchmark_query_and_insert.json:针对单类操作的线程模式极限测试;
  • hold_subscriptions.jsonmany_intersections.json:订阅与失效路径专项压测;
  • search.jsonsearch_debug.jsonvector_search.json:搜索与向量搜索专项;
  • check_dev.jsonempty.json:开发/冒烟用;
  • repro_memory_leak.json:内存泄漏复现场景;
  • prod_with_node_actions.json:生产混合负载 + node actions。

五、编写自定义压测场景

原文档提供了"自定义场景"的完整方法:在 npm-packages/scenario-runner/convex 目录中自行编写 Convex 函数,然后在 workload 配置中以RunFunction场景引用它。

约束与步骤

  1. 函数签名要求:函数名不能带参数(no arguments)。例如query_index.ts中的queryMessagesWithSearch就符合要求;
  2. 将函数放进npm-packages/scenario-runner/convex/目录(如新建your_module.ts,导出export const yourFunction = query({ handler: ... })或对应的mutation/action);
  3. 在 workload JSON 中配置一个RunFunction场景;
  4. 重新npx convex deploy推送函数,再运行 LoadGenerator 并指向新的 workload 配置。

自定义场景配置模板

{ "name": "your_new_workload", "scenarios": [ { "name": "RunFunction", "path": "<your-new-module>:<your-function-name>", "fn_type": "mutation", "rate": 5 } ] }

字段说明:

  • name:场景名,必须为RunFunction(或其他内置场景名);
  • path<模块名>:<函数名>,模块名即convex/.ts文件的 basename;
  • fn_typemutation(写入)、query(查询)或action(动作)三者之一,需与函数实际类型一致;
  • rate:每秒请求数;若要用线程模式,改为"benchmark": <线程数>

场景函数示例

以仓库自带的 query_index.ts 为例,其压测函数queryMessagesWithSearch是典型的"带缓存击穿参数"的查询:通过cacheBreaker随机参数在随机 offset 处查询,使请求均匀分布、避免命中缓存,从而压测真实的数据库查询路径:

export const queryMessagesWithSearch = query({ args: CACHE_BREAKER_ARGS, handler: async ({ db }, { cacheBreaker }) => { // 在随机 offset 处查询,均匀分布、不命中缓存 return await queryMessagesHelper( db, "global", cacheBreaker, 10, "messages_with_search", ); }, }); function queryMessagesHelper( db: DatabaseReader, channel: string, rand: number, limit: number, table: MessagesTable, ) { return db .query(table) .withIndex("by_channel_rand", (q) => q.eq("channel", channel).gte("rand", rand), ) .take(limit); }

编写自定义场景时可以参考这一模式:如果你的目标是压测缓存未命中路径,可以引入随机参数打破查询缓存;如果目标是压测冷路径或索引路径,则聚焦特定索引查询。其余场景(插入、更新、搜索、向量搜索、定时调度、HTTP action 等)可参考insert.tsupdate.tssearch.tsvectorSearch.tsschedule.tshttp.tsopenclaurd.ts等现有实现。

新增场景类型的扩展方式

如果内置场景类型不够用,需要同时修改两端(遵循 npm-packages/scenario-runner/README.md 的扩展指南):

  1. 在 ScenarioRunner 的index.ts中把场景名加入ScenarioName并接入main控制流;
  2. 编写实现IScenario接口、继承Scenario基类的类,放入scenarios目录,并从main控制流调用;
  3. 在 LoadGenerator 的Scenario枚举(main.rs)中新增对应的场景变体。

这样新增的场景就能像内置场景一样被 workload JSON 引用并施加负载。


六、结果解读与指标观测

统计报告

加上--stats-report后,压测结束会打印统计报告。报告内容由 crates/load_generator/src/stats.rs 生成,核心是各类请求的延迟分位数(典型如 p50 / p95 / p99)与错误统计。同时fail_if_too_many_errors()会在错误过多时让进程以非零状态退出——这一点对把压测接入 CI 回归非常有用:可以在每次发布前用固定 workload 对比延迟与错误率是否劣化。

Prometheus 指标导出

使用--metrics-addr参数可启动 Prometheus exporter(如--metrics-addr 0.0.0.0:9100),LoadGenerator 会在该地址暴露指标供采集,代码路径为 performance_stats/exporter.rs 中的register_prometheus_exporter(main.rs)。采集到的指标会带上load_description{workload}_{duration}s)与backend_version标签,方便按 workload 与后端版本维度对比分析。

指标标签

从 main.rs 可见,LoadGenerator 为所有指标附加的关键标签包括:

  • load_description:格式<workload名>_<时长>s,例如prod_60s
  • backend_version:被测后端的版本号(来自健康检查接口);
  • 场景名与函数路径(metrics::log_target_qps会记录每个场景的目标 QPS)。

有了这些标签,就可以在监控系统中按后端版本、负载类型做横向对比,评估新版本是否引入性能回退。


七、注意事项与最佳实践

综合原文档与源码,进行自托管压测时建议遵守以下原则:

  1. 使用专用测试实例npx convex deploy会整体替换实例上的函数,绝不要对生产实例执行;为压测单独部署一个自托管后端。
  2. 区分 rate 与 benchmark 模式:需要模拟真实流量节奏时用rate(每秒请求数);需要测量极限并发能力时用benchmark(线程数)。
  3. 从轻量 workload 开始:先用light.json或自定义的少量场景验证链路(部署、setup、事件回传、报告输出)正常,再逐步加大到heavy.json/prod.json级别的混合负载。
  4. 关注低频后台场景SnapshotExportCloudBackup等场景 rate 极低,主要模拟生产中的偶发重操作,压测时要预留足够时长让它们有机会触发。
  5. 开启 metrics 导出做长期对比:使用--metrics-addr暴露 Prometheus 指标,按backend_version标签追踪每次发布后的性能变化。
  6. CI 集成:利用--once+--stats-report的一次性运行模式和错误退出机制(fail_if_too_many_errors),把压测作为发布前回归检查的一环。
  7. 充分预热数据:workload 顶层的num_rowsnum_vector_rows控制 setup 阶段写入的数据量,测试搜索 / 向量搜索 / 大表查询前应保证数据规模接近真实负载。

参考文档索引

  • 自托管压测入口文档:self-hosted/advanced/benchmarking.md
  • LoadGenerator 官方说明:crates/load_generator/README.md
  • ScenarioRunner 说明:npm-packages/scenario-runner/README.md
  • 核心实现:crates/load_generator/src/main.rs
  • 预置命令:crates/load_generator/Justfile
  • 内置 workload 目录:crates/load_generator/workloads
  • 压测场景函数:npm-packages/scenario-runner/convex
  • 数据库
  • 后端

【免费下载链接】convex-backend

The open-source reactive database for app developers

项目地址:https://gitcode.com/gh_mirrors/co/convex-backend
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询