n = r.eval("local c=redis.call('INCR',KEYS[1]) "
"if c==1 then redis.call('EXPIRE',KEYS[1],60) end "
"return c", 1, key)
下单接口用本地字典计数,单机限 100 次每分钟。扩容到四台之后压测跑出 380 次每分钟,每台各自拦自己的,前端看到的是整体没限住。先别急着动参数,把报错原文和时间点记下来,顺序反了容易白折腾。
原因不复杂,计数器跟着进程走,实例之间互不可见,总阈值等于单机阈值乘以实例数。滚动发布时旧实例的计数还会清零。按 IP 做键的话,代理后面的用户又会被算成一个人。
围绕「多实例限流」排查时,命令行跑一遍比在面板里点十次有用,面板会替你做掉不少隐式操作。备份不是备了就行,恢复一次才算数,很多备份文件打开才发现是空的。
处理上按这个顺序:计数挪到 redis 用 INCR 加 EXPIRE 的原子脚本;键里带上接口名和时间窗口 别用固定键;本地再留一层兜底 防止 redis 抖动时全放行;按用户 id 和 IP 两个维度分别计数 阈值分开配。
改完只确认一件事:四台实例同时压 总请求数在 100 上下 超出的返回 429。
