Redis——MoreKey
MoreKey
1. 问题描述
假如生产的 Redis 数据库里面有 1000W 记录,如何遍历?可以使用 keys *
吗?
2. 问题演示
# 写一个添加一百万数据的文本文件
for((i=1; i<=1000000; i++)); do echo "set k$i v$i" >> /tmp/redisTest.txt; done
# 让 Redis 通过管道执行这个文本文件
cat /tmp/redisTest.txt | redis-cli --pipe
# 连接 Redis
redis-cli
### 以下是在 redis-cli 中执行的命令
# 查看数据库中有多少个键,结果应该 >= 1_000_000
dbsize
# 谨慎使用 keys * 查看,我自己测试的时候花了 7s
keys *
keys *
这个指令有致命的弊端,在生产环境中一定不要使用,这个指令没有限制查询数量的参数,一次性获取所有满足条件的数据。如果有千万级以上的数据,则会导致 Redis 卡顿,所有读写 Redis 的其他指令都会被延后甚至超时报错,更有甚者可能会引起 缓存雪崩 和 数据库宕机。
3. 如何规避这个指令的使用?
如果问到如何规避 keys *
的使用,那就是在问 如何限制危险指令以防止误删误用。可以通过 配置禁用指令 来防止误删误用,直接去配置文件中增加 rename-command keys ""
来解决,实际上效果就是把 keys
这个指令重写为空字符串(需要注意一点,修改配置后记得重启 Redis)。再次执行 keys *
,就会得到如下响应:
(error) ERR unknown command keys, with args beginning with: *
注:除此之外,最好把 flushall, flushdb
这样的 危险指令 也禁用一下。
4. 既然不用 keys *,那应该如何遍历?
使用 scan
指令(类似于 MySQL 中的 LIMIT
):
4.1 基本介绍
- 它有三个比较常用的参数:
- 游标偏移量:起始游标偏移量设置为 0,后续的偏移量由上一次
scan
操作的第一个返回值决定。例如scan 0
中的0
就是游标偏移量。 - 匹配表达式:类似于
keys
匹配时写在其后面的表达式,可以省略,省略时表示匹配所有键。例如scan 0 match *
中的*
表示匹配所有键。 - 统计数量:限制返回数据的最多条数,可以省略,省略时表示最多返回 10 条数据。例如
scan 0 count 100
中的100
表示最多返回 100 条数据。
- 游标偏移量:起始游标偏移量设置为 0,后续的偏移量由上一次
- 它会返回两个值:
- 第一个值是下次使用
scan
指令填写的游标偏移量。 - 第二个值是本次遍历出来的数据。
- 第一个值是下次使用
4.2 实操
进入 redis-cli 后,可以这样使用 scan
指令:
# 输入
scan 0
# 输出
1) "557056"
2) 1) "k107340"2) "k705150"3) "k993878"4) "k314067"5) "k843627"6) "k80648"7) "k34907"8) "k420675"9) "k604082"10) "k801554"
# 输入
scan 557056
# 输出
1) "360448"
2) 1) "k369662"2) "k62155"3) "k997059"4) "k50453"5) "k345387"6) "k930652"7) "k248169"8) "k93122"9) "k399750"10) "k471752"
5. 总结
本文介绍了 Redis 中的 MoreKey 问题,提到了如何通过配置文件限制危险指令的使用,而且还讲解了替换 keys *
的 scan
指令,希望大家在日后的工作中不要出现使用 keys *
导致的生产事故。