为了防止同时过期,代码给 TTL 加了 0 到 300 秒随机,监控显示一千个 key 仍然在同一秒失效,数据库 QPS 瞬间翻六倍。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

int jitter = ThreadLocalRandom.current().nextInt(0, 300);
redis.setex(key, baseTtl + jitter, value);

Random 用了固定 seed,每次进程启动生成的随机序列完全一样,所有 key 拿到的抖动值相同。抖动只在一个模板里算了一次,后面复用了同一个数。这一点先确认清楚,后面就不用反复试。

「TTL 抖动失效」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。

动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。一次只改一处,改完立刻验证,几个改动叠在一起,出问题就说不清是谁导致的。

具体做法是,随机数用 ThreadLocalRandom 不要固定种子;每个 key 独立计算抖动 不要复用模板值;上线后抽样看过期时间分布 确认没有堆在同一秒。

改完照着核一遍,抽样一千个 key 的 TTL 落在 300 到 600 秒之间,过期时间均匀散开,整点 QPS 峰值消失。

作者 9823189