1. 先看下官方对keys这个命令的说明:
返回所有匹配的key.
keys的时间复杂度是O(N),N为执行该命令下的数据库的key的数量,常数。
redis扫描key的速度很快,在入门笔记本大约是40毫秒100w个。
警告⚠️:keys用在生产环境只能以极低频率执行。 在大数据库执行时会出现灾难性的性能。如果需要查询某些key,考虑使用SCAN或者sets。
2. keys命令为什么会这么慢呢?
换个问法,为什么redis需要遍历所有的key才能找到我们需要的key呢?
(1) Redis是NoSQL型数据库,以hash数据结构存储的,所以才能实现高效的数据查询。而hash结构对于精确查找是非常快的,对于模糊查询,则无能为力。
(2) Redis的命令执行是单线程的,同一时间只能执行单个命令。单一长时间命令会堵塞后续。(可以通过debug sleep 0.1100ms 模拟执行长时间命令)
以上两点造成了KEYS进行key查询需要遍历当前db的所有数据,以及当该命令执行完成的时候后续命令都会被堵塞。
因此在redis中执行的命令,尽量避免长时间堵塞命令。
3. 建议使用Scan代替 keys
使用方法参考:Redis 用scan模糊匹配key,避免阻塞_梦~'-CSDN博客
用SCAN cursor [MATCH pattern] [COUNT count]命令以迭代的方式进行key遍历(限制单次查询的key数量)。
这个 count 不是限定返回结果的数量,而是限定服务器单次遍历的字典槽位数量(约等于)。
缺点:
1.同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
2.如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会,redis scan对返回结果集只提供有限的保证。
3.元素如果在迭代过程中被删除了,可能不会被返回。
4.将想要禁止的命令,按以下格式加入配置文件中:
建议直接在配置文件中用redis的rename屏蔽掉这些高危命令:
rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command KEYS ""
5. SCAN和KEYS的区别:
当 KEYS 命令被用于处理一个大的数据库时, 又或者 SMEMBERS 命令被用于处理一个大的集合键时, 它们会锁定redis库, 可能会阻塞服务器达数秒之久。在高并发下会导致请求大量堆积进而导致服务雪崩。有些公司在生产环境直接禁用kyes *命令。但是在redis服务器key的数量不大的情况下,使用keys也是没啥问题的。
SCAN 命令及其相关的 SSCAN 命令、 HSCAN 命令和 ZSCAN 命令都用于增量地迭代 ,它们每次执行都只会返回少量元素,不会阻塞服务器, 所以这些命令可以用于生产环境, 而不会出现像 KEYS 命令、 SMEMBERS 命令带来的问题。
SCAN一样有它自己的问题:
- 因为是分段获取key,所以它会多次请求redis服务器,这样势必取同样的key,scan耗时更长。
- 在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令只能对被返回的元素提供有限的保证。
SCAN cursor [MATCH pattern] [COUNT count]
整合以下大佬文章: