Skip to content
预计 1 分钟右侧目录可快速定位

Harness 多实例怎样共享短期协调状态:Redis、Atomic Operations 与 Distributed Rate Limit ​

前置:Harness 哪些数据值得缓存:Cache Aside、TTL、Invalidation 与 Stampede
核心问题:多实例 Harness 怎样用 Redis 做原子限流/短期协调,又为什么不能因此把 Redis 当成所有 Runtime 权威状态?

单机 Semaphore 到多实例后为什么失效 ​

假设 Provider 给某 tenant 每秒最多 100 次请求:

text
worker A local limit = 100
worker B local limit = 100
worker C local limit = 100

三个实例各自“没有超限”,合起来却可能达到 300。需要一个跨实例共享的 rate state。

Redis 的价值就在这里:低延迟、共享、提供可组合的原子操作。但它不是自动变成 Workflow database。

先把 Redis 定位成 Coordination Plane ​

适合:

text
rate-limit counters / token bucket state
short-lived dedup hints
single-flight locks
cache metadata
presence / ephemeral heartbeat
某些 lease primitive 的实现层

通常不把以下事实仅存在 Redis 里:

text
Run final status
Checkpoint history
Approval evidence
Tool completion audit
long-lived event log

如果 Redis 重启/淘汰一条 key 就会让系统“不知道任务做到哪”,边界就错了。

Data Structure 从需要的原子操作倒推 ​

不要先说“统一用 Hash/String”:

  • Counter:配额计数;
  • Set:短期 membership/dedup;
  • ZSet:按时间排序的窗口或到期项;
  • Hash:小型结构化 coordination state;
  • Stream:有消费语义的事件流,但一旦承担 durable job delivery,就必须按 Queue 的 ack/redelivery 模型设计。

关键不是结构名字,而是:这个状态允许丢吗、允许 stale 吗、需要哪个原子 transition?

Atomic 只代表“Redis 内部没中间态” ​

INCR、conditional SET、Lua 等可以原子更新 Redis 数据,但不能自动得到:

text
Redis update
+
Postgres commit
+
remote Tool call

三者的跨系统原子性。

例如 Worker claim 的语义需要 lease/fencing,即使底层用 Redis 实现,也要遵守 09-09 的 stale-owner rejection;不能因为 SET NX 成功就宣布 exactly-once。

Distributed Rate Limit 要定义四件事 ​

  1. Subject:按 tenant、user、provider、tool 还是 credential 限?
  2. Cost:每请求 1 token,还是按模型 token/Tool weight?
  3. Time semantics:fixed/sliding/token bucket 的窗口与时钟来源;
  4. Failure policy:Redis 不可用时 fail-open、fail-closed 还是降级到本地限制?

对高成本 Provider,fail-open 可能造成成本洪峰;对关键交互 API,完全 fail-closed 又可能扩大 Redis 故障。策略必须写入 policy,而不是藏在客户端异常处理里。

Failure Modes ​

Redis 成为第二套 RunState ​

后果: DB 与 Redis 状态漂移,不知道哪个是真的。

处理: durable Runtime facts 单一 authority;Redis 保存可重建 coordination/cache state。

Rate Limit Key 太粗 ​

后果: 一个 tenant 把所有用户饿死,或不同 credential 共享错误 quota。

处理: key 明确 subject/credential/provider/version,并记录拒绝原因用于 observability。

如何验证 ​

场景必须成立
3 个 worker 同时压测同一 Provider quota总体请求仍被统一限制
Redis 短暂不可用行为符合明确 fail-open/closed/degraded policy
Redis 全量清空后恢复durable Run facts 不丢失

自测 ​

  1. 两个 Harness 实例同时做限流,如果各自只用进程内计数器,会出现什么全局偏差?
  2. 为什么需要 Redis 原子操作而不是 GET→本地计算→SET 三步完成分布式计数?

Sources ​

AI Engineering · Agent · Harness · Backend Systems