redis 在生产环境下执行keys的危害

问题描述

最近碰到一前同事在群里聊天,说因为错误使用keys导致生产事故,为此他差点失业(玩笑),下面是他的自白(事件回顾):

在这里插入图片描述
在这里插入图片描述

问题分析

为什么测试,灰度环境使用keys没有导致任何问题,而到生产环境会导致服务挂了呢?
这个问题首先得从keys这个命令说起。
先看下官方对这个命令对说明:

Available since 1.0.0.
Time complexity: O(N) with N being the number of keys in the database, under the assumption that the key names in the database and the given pattern have limited length.
Returns all keys matching pattern.

While the time complexity for this operation is O(N), the constant times are fairly low. For example, Redis running on an entry level laptop can scan a 1 million key database in 40 milliseconds.
Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance when it is executed against large databases. This command is intended for debugging and special operations, such as changing your keyspace layout. Don’t use KEYS in your regular application code. If you’re looking for a way to find keys in a subset of your keyspace, consider using SCAN or sets.

看不懂的同学我直接翻译下大致意思:
返回所有匹配的key.
keys的时间复杂度是O(N),N为执行该命令下的数据库的key的数量,常数。
redis扫描key的速度很快,在入门笔记本大约是40毫秒100w个。
警告⚠️:keys用在生产环境只能以极低频率执行。 在大数据库执行时会出现灾难性的性能。如果需要查询某些key,考虑使用SCAN或者sets

一位老哥冒死执行的结果:
在这里插入图片描述
近1200w的key数量,执行时间约1.35s,大约100ms扫描100w的key。这速度比官方声明的要慢,可能是因为该服务器有其他应用占用了cpu。

这个命令为什么会这么慢呢?
换个问法,为什么redis需要遍历所有的key才能找到我们需要的key呢?

  1. Redis是NoSQL型数据库,以hash数据结构存储的,所以才能实现高效的数据查询。而hash结构对于精确查找是非常快的,对于模糊查询,则无能为力。
  2. Redis的命令执行是单线程的,同一时间只能执行单个命令。单一长时间命令会堵塞后续。(可以通过debug sleep 0.1100ms 模拟执行长时间命令)

以上两点造成了KEYS进行key查询需要遍历当前db的所有数据,以及当该命令执行完成的时候后续命令都会被堵塞。
因此在redis中执行的命令,尽量避免长时间堵塞命令。

改进方法

使用SCAN cursor [MATCH pattern] [COUNT count]命令以迭代的方式进行key遍历(限制单次查询的key数量)。
这个 count 不是限定返回结果的数量,而是限定服务器单次遍历的字典槽位数量(约等于)。
缺点:
1.同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
2.如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。
3.元素如果在迭代过程中被删除了,可能不会被返回。

redis 127.0.0.1:6379> scan 0 match * count 1000 
1) "17"
2)  1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
    10) "key:7"
    11) "key:1"

redis 127.0.0.1:6379> scan 17 match * count 1000
1) "0"
2) 1) "key:5"
   2) "key:18"
   3) "key:0"
   4) "key:2"
   5) "key:19"
   6) "key:13"
   7) "key:6"
   8) "key:9"
`
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咕咕咕zhou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值