Appearance
Harness Worker 怎么扩容而不压垮 Provider/DB:Concurrency、Prefetch 与 Backpressure
前置:Worker 失败后怎样重投而不重复副作用:Idempotent Worker、Retry Queue 与 DLQ
核心问题:Worker 数量翻倍为什么可能让系统更慢,Concurrency、Prefetch 与 Backpressure 应怎样匹配 Provider/DB 容量?
Queue 长了,不代表“加 Worker”一定正确
假设:
text
DB pool = 30
Provider concurrency quota = 50
Tool API limit = 20
worker processes = 40 × concurrency 20 = 800 in-flight800 个 worker slot 不会创造新的下游容量,只会制造更多等待、timeout 和 retry。
因此 Worker 的并发上限要从最窄下游资源反推,而不是从 CPU 数或 backlog 长度直接推。
并发应该分层,而不是一个全局数字
一个 Harness 常同时有:
text
model slots
read-only tool slots
write-side-effect tool slots
sandbox slots
DB-heavy jobs
CPU-heavy jobs不同 job class 的成本和风险不同。可以按 Tool/resource class 建独立 semaphore/worker pool,使一个慢 Provider 不把所有本地文件 Tool 一起饿死。
Prefetch 过大只是把 Broker Queue 搬到 Worker 内存
如果每个 worker 一次取 100 条,但实际并发只处理 5 条:
- 95 条被某个 worker 私有占住;
- fairness 变差;
- worker crash 后大量 redelivery;
- cancel 后 stale work 仍滞留本地。
Prefetch 应与实际可执行并发和处理时长匹配。长任务通常更保守。
Backpressure 要一路传回入口
真正的链路:
text
Provider/DB saturation
→ worker concurrency stops growing
→ queue wait/depth rises
→ scheduler slows fan-out
→ admission control delays/rejects low-priority Run
→ API 返回明确 overload/deferred state如果只让 Queue 无限增长,用户看到的是数小时后的陈旧任务,而系统内部还误以为“请求都接收成功”。
Fairness:一个大 Run 不能吃光所有 Worker
需要考虑:
- per-tenant in-flight cap;
- per-run fan-out cap;
- priority class;
- aging,避免低优先级永久饥饿;
- sandbox/expensive Tool 单独配额。
这些 policy 的目标不是绝对公平,而是防止单一 workload 把共享 Harness 拖死。
应该监控什么
仅看 Queue depth 不够。至少组合:
text
queue wait time
oldest job age
worker utilization
in-flight by resource class
DB pool wait
HTTP pool wait
Provider 429/timeout
retry rate
tenant fairness只有 backlog 高、下游仍有余量时,加 worker 才可能改善吞吐。
Failure Modes
Autoscale 只看 Queue Depth
后果: Provider 已 429,扩 worker 又制造更多 429/retry storm。
处理: backlog + downstream saturation + service time 联合判断。
Prefetch 远大于实际并发
后果: work 被少数 worker 囤积,cancel/fairness/redelivery 变差。
处理: prefetch 与真实 slot 对齐,长 job 小 prefetch。
如何验证
| 场景 | 必须成立 |
|---|---|
| DB pool 固定 20,持续增加 worker | DB wait 不无限增长;系统停止扩大并发 |
| Provider 开始持续 429 | worker 消费降速而不是继续扩容 |
| 单 Run fan-out 1000 nodes | 其他 tenant 仍有执行机会 |
自测
- 增加 Worker 后吞吐没升,Provider 429 和 DB pool wait 反而暴涨。此时该继续加并发还是收紧 concurrency/prefetch?为什么?
- Queue depth 持续增长时,backpressure 应保护的是“队列看起来短”还是下游容量与系统稳定性?