Redis执行KEYS命令导致后续请求超时,根本原因是其单线程模型被O(n)全量扫描阻塞;应立即停用KEYS,改用SCAN分批迭代,并结合slowlog分析、bigkeys清理、连接池调优及系统资源排查进行综合治理。

如果您在Redis中执行KEYS命令后观察到所有后续请求均出现超时现象,则极可能是由于KEYS *等全量扫描操作引发主线程长时间阻塞。Redis采用单线程事件循环模型,任何O(n)复杂度的命令都会独占CPU资源,导致排队中的其他命令无法及时响应。以下是定位与缓解该问题的具体步骤:
一、立即停止KEYS类命令并启用SCAN替代
KEYS命令会遍历整个键空间,无分批机制、不可中断、不反馈进度,在键数量达数万时即可造成数百毫秒至秒级阻塞。SCAN命令以游标方式分批次迭代,每次执行时间可控,且不会阻塞主线程。
1、在客户端中终止正在运行的KEYS命令(若支持中断)。
2、使用redis-cli连接服务端,执行SCAN 0 MATCH * COUNT 100进行小批量扫描。
3、记录返回的游标值,重复执行SCAN命令直至游标返回0,完成全量遍历。
4、将原有脚本或定时任务中所有KEYS *或KEYS pattern替换为SCAN循环逻辑。
二、检查慢查询日志定位历史阻塞源
Redis内置slowlog功能可捕获执行时间超过阈值的命令,默认记录耗时≥10000微秒(10ms)的操作。该日志不包含网络传输与排队延迟,仅反映命令实际执行耗时,是识别KEYS类高危指令的关键依据。
1、登录Redis服务器,执行redis-cli slowlog get 10获取最近10条慢日志。
2、查看输出中第三字段(微秒级耗时)是否持续高于50000(50ms),并确认第四字段命令是否为keys、hgetall、smembers或sort。
3、执行redis-cli config set slowlog-log-slower-than 1000将阈值下调至1ms,提升对毫秒级异常的敏感度。
4、通过redis-cli slowlog reset清空历史记录,避免干扰后续监控。
三、识别并清理大Key以消除隐性阻塞点
除KEYS外,对大Key执行HGETALL、SMEMBERS等命令同样会触发内存一次性加载与序列化,导致响应延迟激增。一个含5万成员的SET可能生成数MB响应体,不仅拖慢当前连接,还会挤占网络缓冲区与客户端解析资源。
1、运行redis-cli --bigkeys命令自动扫描各类型数据结构中的潜在大Key。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
2、对检测出的String类型value > 5MB、集合类元素 > 2000个的Key进行标记。
3、使用MEMORY USAGE keyname精确获取其内存占用字节数。
4、针对高频访问的大Key,拆分为带分片标识的多个小Key,例如将user:1001:profile重构为user:1001:profile:base与user:1001:profile:ext。
四、调整客户端连接池参数降低堆积风险
当Redis主线程被阻塞时,客户端未完成的请求将在连接池中持续排队。若连接池最大等待时间(MaxWaitMillis)设置过长,将加剧超时扩散;若连接数上限(MaxTotal)不足,则新请求直接失败。
1、将JedisPoolConfig中的maxWaitMillis设为≤2000毫秒,避免无效等待。
2、将maxTotal提升至业务峰值QPS的2–3倍,防止连接耗尽。
3、启用testOnBorrow = true确保每次获取连接前执行PING探测,剔除已断连实例。
4、配置minIdle不低于5,维持基础可用连接保有量。
五、验证Redis进程资源占用排除外部干扰
即使未执行KEYS命令,若Redis所在宿主机存在CPU争用或内存交换(swap),也会导致命令执行延迟升高。此时客户端超时并非由Redis内部逻辑引起,而是底层系统资源受限所致。
1、执行top -p $(pgrep redis)观察Redis进程CPU使用率是否长期高于80%。
2、运行redis-cli info memory | grep mem_fragmentation_ratio,若结果1.0,说明发生内存交换。
3、检查/proc/$(pgrep redis)/smaps中Swap与SwapPss字段是否非零。
4、确认Redis未与CPU密集型服务(如Elasticsearch、Flink)混部在同一物理节点。

















