任务队列容量压测与验收边界
10 月 9 日,我补充了一个异步任务系统的容量压测。当天的 k6 smoke 完成了 42 个任务,未发现重复,观察到的执行槽占用峰值为 8;容量验收报告的结论却仍是 accepted=false。
这几个结果可以同时成立。任务跑通说明当前样本的执行链路可用,容量验收还要回答目标负载、等待时间和持续运行是否达标。本文根据当天记录事后整理,项目信息已匿名化,数字来自当时的报告。
先把提交请求和任务完成分开
异步接口通常只负责创建任务。HTTP 返回成功后,任务还要经过排队、领取、执行和结果持久化。假如压测只统计提交接口的响应时间,得到的可能是一条很漂亮的曲线,队列却在继续增长。
这次需要观察的是完整任务链路:
提交请求 → 创建任务 → 排队 → Worker 领取 → 执行 → 记录终态一次提交还可能触发多次查询或轮询。因此,我在读结果时先分清以下单位:
| 指标 | 回答的问题 |
|---|---|
| 迭代启动速率 | 压测脚本按什么速度开始执行场景 |
| HTTP 请求数 | 场景实际发出了多少个 HTTP 请求 |
| 任务创建数与完成数 | 进入队列的任务最终去了哪里 |
| 执行槽占用 | 同时有多少任务占用执行资源 |
| 排队时间与完成时间 | 用户需要等多久 |
k6 的 constant-arrival-rate 配置的是每个时间单位启动多少次迭代。一轮迭代可以发一个请求,也可以提交任务后持续查询状态,不能把配置中的 rate 直接写成 HTTP RPS。k6 官方文档对此有明确说明。
同样,峰值占用 8 个执行槽,不等于 8 个虚拟用户,也不能换算成系统支持多少个真实用户。用户提交频率、单个任务耗时和外部服务配额都会影响队列。
smoke 报告里的三个数字
当天报告记录如下:
| 观察项 | 结果 | 结论范围 |
|---|---|---|
| 完成任务数 | 42 | 这批 smoke 任务完成了 |
| 重复任务检查 | 未发现重复 | 本次样本没有观察到重复 |
| 执行槽占用峰值 | 8 | 本次运行观察到这一峰值 |
| 容量验收结果 | accepted=false | 报告未判定容量验收通过 |
这里的 accepted 是容量验收报告的判断字段。它不是某个业务提交接口返回的“请求是否接受”,也不表示那 42 个任务被拒绝。
smoke 的价值是先确认压测脚本、提交路径和任务终态对账能串起来。它还不足以替代目标容量测试。尤其是“未发现重复”,必须带着样本范围阅读:这批任务没有重复,不能据此承诺以后所有故障恢复和重试都不会重复。
这次压测实现已经合入代码基线,smoke 跑通,容量验收尚未通过。
结果对账比请求成功率多一步
对任务系统而言,压测结束时间未必等于所有任务结束时间。如果仍有排队和执行中的任务,需要留出明确的收尾窗口,再检查每个提交记录对应的任务终态。
下面用简化伪代码演示任务终态对账:
for (const submission of submissions) { const task = tasksById.get(submission.taskId); if (!task) recordProblem("missing-task", submission.taskId); else if (!terminalStates.has(task.status)) { recordProblem("unfinished-task", task.id); }}实际检查还要有业务定义:同一个幂等键对应几条任务,失败和取消是否属于允许的终态,重试是否产生重复执行或重复结果。仅用“提交次数减去完成次数”做差,解释不了失败、取消以及幂等重放。
持续容量测试还应观察队列是否越积越多。任务能够最终完成,但等待时间一直上升,说明测试期间的到达速度与处理速度已经失衡。只截取最后完成的任务,会把仍在等待的任务从统计中漏掉。
dropped_iterations 也要检查来源
k6 的 dropped_iterations 统计没有启动的迭代。预分配的虚拟用户不足,或迭代变慢占住虚拟用户,都可能让计划中的迭代无法启动;它不能直接解释成“服务端丢了这些请求”。官方说明区分了压测配置不足与被测系统响应变慢等原因。
遇到这个指标,先确认计划负载是否真的施加到了系统,再结合请求耗时、迭代耗时和服务端队列曲线判断。否则可能把压测机的限制写成系统容量,也可能因为实际到达速率下降而误以为服务端已经稳定。
JSONB 大小边界是另一项检查
当天还做了任务 JSONB 大小边界试验。它检查的是大输入在存储与校验路径上的行为,不能和吞吐测试合并成一个“通过”结论。
任务数量相同,载荷大小不同,数据库传输、序列化和内存占用也会不同。对允许用户提交结构化内容的接口,容量测试至少要记录载荷的规模;边界测试则应在隔离环境里检查临界值两侧的行为,以及被拒绝的输入有没有留下半条任务或不完整状态。
这次边界试验的结果尚不足以确定可复用的接口大小上限。应用对载荷的限制,需要结合校验、传输和运行资源确定,也不能等同于 PostgreSQL JSONB 的通用容量上限。
如果要继续做正式验收,我会先固定目标到达速率、任务类型与大小分布、持续时间、排队与完成时间门槛,再保存压测配置、代码版本和结果工件。这样下一轮才能回答“在什么条件下达到什么容量”。这次完成了 42 个任务的 smoke,容量报告没有通过验收。