bigywater.tech
Redis · 119

KEYS 的风险

「生产上不要用 KEYS」几乎是 Redis 的第一条军规。它到底有多危险?危险与什么有关?这篇在 10 万到 300 万个 key 的库上量 KEYS 的阻塞时间,对比 SCAN,并演示怎么从权限上直接禁掉它。

123 ms
100 万个 key 时 KEYS * 让另一个连接 PING 的最大停顿
185 ms
300 万个 key 时,几乎没有匹配的 KEYS 造成的停顿(遍历本身的代价)
1.89 ms
SCAN COUNT 1000 遍历 300 万个 key 期间 PING 的最大停顿

KEYS 的代价

每个库大小测两次:KEYS * 与 KEYS nomatch*;另一个连接每 0.5 ms 发一次 PING
实测 · 本机执行输出
    key 总数      KEYS * 命令耗时 ms      PING 最大停顿 ms    KEYS nomatch* 耗时 ms      PING 最大停顿 ms
    100000                  70              30.9                      4               4.3
    500000                 339              52.4                     23              22.0
   1000000                 702             123.1                     43              41.8
   3000000                2181             424.5                    185             185.2

停顿随 key 数近似线性增长:10 万个 key 31 ms、100 万个 123 ms、300 万个 424 ms。对没有匹配的模式,命令耗时和停顿都小很多(185 ms @ 300 万),因为不用构造大回复——但遍历部分的开销没有免除:危险与「key 总数」有关,与「匹配了多少」关系不大。

替代:SCAN

实测 · 本机执行输出
  3000000 个 key:SCAN 遍历总耗时 2658 ms(2998 次调用),期间另一个连接 PING 最大停顿 1.89 ms

SCAN COUNT 1000 遍历 300 万个 key,2998 次调用共 2658 ms,期间 PING 最大停顿 1.89 ms。总耗时和 KEYS 一个量级,但每次只占主线程很短一段。

从权限上禁用

实测 · 本机执行输出
> KEYS *
(error) NOPERM User app has no permissions to run the 'keys' command
> GET key:1
"v"

ACL 可以把 keys 从某个用户的权限里去掉:该用户执行 KEYS 得到 NOPERM,其它命令不受影响。ACL 的细节见第 122–125 篇。

分步演示:KEYS 的阻塞

KEYS 的风险
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。单实例,key 形如 key:N,值 v;PING 探测间隔 0.5 ms;数字是单次测量
    • 没有验证:key 名更长或库里有大 key 时的耗时、集群/多库下的行为、rename-command 方式禁用(第 131 篇)、KEYS 在 Lua 中被调用时的行为
    京ICP备2026067502号-1京公网安备11010502063487号