这类问题我又碰上了一次。Redis 6.2 单实例,八百万个 key,运维排查问题时在客户端敲了一次 keys user:*,随后两秒内所有接口报超时,应用的 Redis 客户端日志里全是 timeout 3000ms。
第一反应是「客户端超时后自动重试,重试请求又堆在同一个实例上,把阻塞时间拉长」,验证下来不成立。
真正麻烦的地方在于,几个原因的现象几乎一样。keys 是 O(N) 全量遍历,单线程执行期间一条其他命令都处理不了;键空间越大遍历越久,八百万 key 扫一遍要几百毫秒到数秒;监控脚本里也有同样的写法,每分钟跑一次,平时就在偷偷制造毛刺。
第一件事是确认是命令阻塞还是网络问题
redis-cli slowlog get 10
然后看这条命令被调用了多少次
redis-cli info commandstats | grep -i cmdstat_keys
接着用游标遍历替代全量匹配
redis-cli --scan --pattern 'user:*' | head -20
等前面都确认过,再在配置里禁用这条命令,避免有人再敲
printf 'rename-command KEYS ""\n' >> /etc/redis/redis.conf && systemctl restart redis
怎么算真的好了,看的是同一批现象。slowlog 里不再出现 keys 相关记录,接口的超时告警归零,命令统计里 keys 的调用次数停止增长。
这里还有个坑。scan 也不是免费的,count 设太大同样会卡;禁用命令要重启,安排在低峰期做更稳妥。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
