一个惊群问题的处理

在一个 side project 里遇到这样一个问题:后台要处理客户端对千万级远程数据集的查询,而上游接口限速严重。为了避免频繁撞 429,尝试全量拉取为本地缓存同时作为本地主库用于索引。但部分数据会随机更新,需要按 TTL 回源刷新。

关键在于,一次 dry run 导入的数据时间分布很集中,导致后续 TTL 也集中到期,形成批量回源再次撞限流。这是典型的惊群,但它不是多 worker 监听 socket 阻塞 accept 那种内核唤醒型惊群,而是过期时间对齐导致的回源惊群。

Claude Opus 4.6 给出了一个简洁的低侵入方案,用 Jitter TTL 做确定性抖动解决了问题,把 item_id 映射为稳定整数并归一化,实现了参考基准 TTL 让缓存分散过期。

1
2
3
4
5
def _jitter_ttl(ttl: int, item_id: int) -> int:
h = hash(item_id) & 0xFFFFFFFF
ratio = (h % 10000) / 10000.0 # 0.0 ~ 0.9999
jitter = int(ttl * 0.4 * (ratio - 0.5)) # ±20% of TTL
return max(ttl + jitter, _DAY)

这个 overlay 方案不需要重构已有队列、锁和调度,没有额外状态,每次运行行为一致,能按需 ignore,记录在此。