Redis7_11 高阶篇 第二章 Redis的BigKey

本文讨论了在阿里广告平台处理海量数据时查询特定前缀的高效方法,避免误删命令,介绍了内存使用管理和BigKey问题的识别、删除策略,以及如何通过配置和替代命令来优化Redis性能,避免keys*命令带来的风险。

面试题

阿里广告平台,海量数据里查询某一固定前缀的key?
小红书,你如何生产上限制keys */flushdb/flushall等危险命令以防止误删误用?
美团,MEMORY USAGE 命令你用过吗?
BigKey问题,多大算big? 你如何发现? 如何删除? 如何处理?
BigKey你做过调优吗? 惰性释放lazyfree了解过吗?
Morekey问题,生产上redis数据库有1000W记录,你如何遍历? key *可以吗?

1 为什么要禁用keys */flushdb/flushall

对于100w简单的string类型的value,使用keys *读取,大约花费15-30s,甚至更多,删除却只需要2秒多。如下图

可以看到,读取大数量key 线程阻塞的时间非常恐怖,而删除大数量的key时间也非常短。二者命令,无论哪一个,都是实际生产非常危险的。

如何禁用这三个命令?

配置文件中添加以下配置即可。

配置完成后,请重启后再试。

keys *的替代命令 scan

scan cursor [Match pattern] [Count count]
  • cursor         游标,首次使用应当设置为0,命令返回的首个结果,就是下次使用命令的cursor
  • pattern         匹配自定义类型的key
  • count         设定一次获取多少个(注意,scan命令不能保证一定获取count个key)

SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。

SCAN 返回一个包含两个元素的数组, 

第一个元素是用于进行下一次迭代的新游标, 

第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。如果新游标返回零表示迭代已结束。

SCAN的遍历顺序

非常特别,它不是从第一维数组的第零位一直遍历到末尾,而是采用了高位进位加法来遍历。之所以使用这样特殊的方式进行遍历,是考虑到字典的扩容和缩容时避免槽位的遍历重复和遗漏。

2 BigKey

多大视为BigKey?

String类型的要在10kb以内。

hash、lilst、set、zset的元素个数不能超过5000。

由阿里云Redis开发规范指出:

BigKey的危害

  • 内存不均,集群迁移困难
  • 超时删除,大key删除作梗
  • 网络流量阻寨

怎么产生的?

汇总统计

如报表,zset常年累计。

日常类

如某视频,用户 ,内容爆火,粉丝量骤增。

如何发现?

两个命令 redis-cli --bigkeys 和 memory usage

redis-cli --bigkeys

作用:

给出每种数据结构Top 1 bigkey,同时给出每种数据类型的键值个数+平均大小

用法:

例如:redis-cli -h 127.0.0.1 -p 6379 -a 111111 --bigkeys

也可以设置每隔 100 条 scan 指令就会休眠 0.1s,ops 就不会剧烈抬升,但是扫描的时间会变长

        redis-cli -h 127.0.0.1 -p 7001 –-bigkeys -i 0.1
演示:
找到了list中最大的是list
string类型的找到了k2和k3

memory usage

计算某个key的大小

memory usage key [Samples count]

如何删除

String类型的bigkey可以使用del key来删除,过于庞大的要用unlink

非String类型的bigkey要使用hscan,sscan,zscan方式渐进式删除

hash bigkey的删除

使用hscan每次获取少量字段,再用hdel删除各个字段。

每次使用hscan扫描hashkey中的100个字段,使用hdel删除这一百个字段,不断扫描字段,删除字段,直到scan返回了0(表示字段已经获取完了)才停止删除字段。此时的hash里已经没有字段了,可以直接使用del hashkey 来删除 hash的bigkey。

list bigkey的删除

使用ltrim逐步删除,直到全部删除完成。

jedis.ltrim(key, start, end):这个方法用于保留指定列表中的指定区间的元素,其他元素将被删除。

  • key:列表的键名
  • start:保留的起始位置,0 表示第一个元素
  • end:保留的结束位置

先获取list的长度

每次从左侧删掉100个,并且对删除操作计数

直到删完整个list的所有元素,再删除list本身

set bigkey的删除

类似hash 使用sscan获取部分元素,再用srem删除部分元素,不断进行删除操作,直到删除完set里的所有元素,在删除set本身。

zset bigkey的删除

使用zscan每次获取部分元素,再使用ZREMRANGEBYRANK命令删除每个元素

ZREMRANGEBYRANK:用于移除有序集合中排名(rank)在指定区间内的成员

ZREMRANGEBYRANK key start stop
  • key:有序集合的键名
  • start:起始排名(从 0 开始),包括指定的成员
  • stop:结束排名,包括指定的成员

3 BigKey调优

以下是三个配置的详细解释

配置一 lazyfree-lazy-server-del 

在 Redis 中,lazyfree-lazy-server-del 参数控制服务器如何处理删除请求。下面是对该配置的解释:

  1. 作用
    lazyfree-lazy-server-del 参数用于控制在服务器删除键时,是否以惰性方式释放键所占用的空间。在 Redis 中,删除键并不会立即释放该键所占用的内存,而是通过一种"惰性"的方式进行释放,这有助于减少删除操作的时间消耗。

  2. 参数设置

    • 当 lazyfree-lazy-server-del 被设置为 "no" 时,每次删除操作都会尽可能地立即释放被删除键所占用的内存。
    • 当 lazyfree-lazy-server-del 被设置为 "yes" 时,Redis 会将删除操作的内存释放延迟到后续时刻,避免在删除短时间大量键时产生过多的内存回收操作,从而提高删除操作的性能。

配置二 replica-lazy-flush

在 Redis 中,replica-lazy-flush 参数用于配置主从(replica)节点在复制过程中的行为。下面是对该配置的解释:

  1. 作用
    replica-lazy-flush 参数用于控制主节点向从节点同步数据时的策略。它影响了主节点何时将数据刷新到从节点上以及何时执行磁盘上的数据同步。

  2. 参数设置

    • 当 replica-lazy-flush 被设置为 "no" 时,主节点在向从节点同步数据时会尽可能快地将所有数据刷新到从节点上,从而确保快速的数据同步,但会增加网络流量和主节点的负载。
    • 当 replica-lazy-flush 被设置为 "yes" 时,主节点将采用一种“懒惰”策略,在一定程度上延迟将数据刷新到从节点上,以减少网络流量和主节点的负载。这意味着主节点会在一段时间内收集多个命令,然后一次性地发送给从节点,从而减少数据同步的频率。

配置三   lazyfree-lazy-user-del

Redis 中的 lazyfree-lazy-user-del 配置选项是用来控制用户显式执行 DEL 命令时,是否采用异步删除(lazy free)策略来释放内存中的键值对。

默认情况下,当 Redis 收到一个 DEL 命令请求删除一个键时,它会立即同步地从数据库中删除这个键,并释放其占用的内存资源。这种操作可能会引起阻塞,特别是当删除大对象(比如包含大量元素的集合或哈希表)时,释放内存的过程可能会消耗较长时间,影响服务其他客户端请求的性能。

启用 lazyfree-lazy-user-del 后(设置为 yes),Redis 在接收到 DEL 命令时并不会立即删除并释放内存,而是将删除任务放入后台线程中异步执行。这样做的好处在于,主线程可以快速返回继续处理其他客户端请求,从而提高 Redis 对高并发场景的响应速度和整体性能。

4 总结

阿里广告平台,海量数据里查询某一固定前缀的key?

答:使用keys pattern来查询,但是面度大数量的数据,不推荐。

使用scan cursor [Match pattern] [Count count] 来限制匹配模式,和数量,是更好地选择。


小红书,你如何生产上限制keys */flushdb/flushall等危险命令以防止误删误用?

答:可以在配置文件加上 rename-command keys ""  来加以限制。


美团,MEMORY USAGE 命令你用过吗?

答:用过,这是用来查询特定key占用了多大内存的命令

memory usage key [Samples count] 对于嵌套式数据还可以加上一个count来表示抽样查询该key内的元素的个数,设为0表示查询所有。


BigKey问题,多大算big? 你如何发现? 如何删除? 如何处理?

答:String类型认为大于10k就算bigkey。其余类型的元素个数超过5000就视为bigkey。

使用 redis-cli -a 111111 --bigkeys 和 memory usage来发现他们

使用del 或 unlink来删除string类型的key

其余类型要配合scan来渐进式删除


BigKey你做过调优吗? 惰性释放lazyfree了解过吗?

答:可以在配置文件上设置懒惰模式,延后删除操作的释放内存的时间,优化数据同步策略,添加异步删除的配置等等。


Morekey问题,生产上redis数据库有1000W记录,你如何遍历? key *可以吗?

答:不能用keys * 会阻塞主线程非常长的时间,很危险。

要用scan cursor pattern count命令来少量多次的遍历

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤尘Java

感谢认可!感谢您的打赏!

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

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

打赏作者

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

抵扣说明:

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

余额充值