Redis中BigKey与MoreKey优化笔记

1.MoreKey

在Redis中,MoreKey问题通常指的是当数据库中的key数量非常多时,使用如KEYS *这样的命令去检索所有的key,这会导致Redis服务阻塞,影响正常业务。因为Redis是单线程操作的,执行这类命令时会占用大量时间,从而阻塞其他操作。

keys * 这个指令有致命的弊端,在实际环境中最好不要使用

这个指令没有offset、limit 参数,是要一次性吐出所有满足条件的key,由于redis是单线程的,其所有操作都是原子的,而keys算法是遍历算法,复杂度是O(n),如果实例中有千万级以上的 key,这个指令就会导致Redis服务卡顿所有读写Redis 的其它的指令都会被延后甚至会超时报错,可能会引起缓存雪崩甚至数据库宕机。

生产上限制 keys * /flushdb/flushall等危险命令以防止误删误用?

通过配置文件设置禁用这些命令,redis.conf在SECURITY这一项中

为了避免MoreKey问题,Redis提供了SCAN命令,它是一个基于游标的迭代器,用于以增量的方式迭代数据库中的key。SCAN命令不会像KEYS *那样一次性返回所有的key,而是返回一个游标和一批key,用户可以使用返回的游标进行下一次迭代,直到游标返回0,表示迭代结束。这种方式可以避免阻塞Redis服务,并且可以自定义每次迭代返回的key数量,减少一次性返回大量key对性能的影响。

Scan命令用于迭代数据库中的数据库键

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

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

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

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

SCAN的遍历顺序

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

在实际使用中,应该避免使用KEYS *这样的命令,而是采用SCAN及其相关的迭代命令来处理大量key的情况。这样可以有效地避免Redis服务因处理大量key而造成的阻塞,确保Redis的性能和稳定性

2.BigKey

Redis中的BigKey指的是那些值(value)特别大的键(key),这可能包括大的字符串或者包含大量元素的集合类型(如list、set、hash、zset等)。BigKey的存在可能会导致Redis的性能问题,因为Redis是单线程操作的,处理BigKey时可能会阻塞其他操作,影响整体性能。

通常我们说的BigKey,不是在值的Key很大,而是指的Key对应的value很大

string和二级结构

  • string是value,最大512MB 但是≥10KB就是bigkey

  • list、hash、set和zset,value个数超过5000就是bigkey

    list:一个列表最多可以包含2^32-1个元素(4294967295,每个列表超过40亿个元素)。

    hash:Redis中每个hash可以存储2^32-1个键值对(40多亿)

    set:集合中最大的成员数为2^32-1(4294967295,每个集合可存储40多亿个成员)

3.Bigkey危害、产生与发现

3.1 危害

  • 内存使用不均:在集群模式下可能导致某些节点内存使用过高。
  • 请求阻塞:操作BigKey可能耗时较长,阻塞其他请求。
  • 网络拥塞:BigKey可能会占用大量带宽,影响其他服务。
  • 删除时阻塞:删除操作可能会阻塞Redis,尤其是在BigKey设置了过期时间后

3.2 产生

  • 社交类 明星粉丝列表,典型案例粉丝逐步递增,热点事件

  • 汇总统计 某个报表,日月年经年累计

3.3 发现

redis-cli --bigkey命令:给出每种数据结构Top 1 bigkey。同时给出每种数据类型的键值个数+平均大小

缺点:想查询大于10kb的所有key,--bigkeys参数就无能为力了,需要用到memory usage来计算每个键值的字节数

redis-cli --bigkeys -a 111111
redis-cli -h 127.0.0.1 -p 6379 -a 111111 --bigkeys

#加上 -i 参数,每隔100 条 scan指令就会休眠0.1s.ops就不会剧烈抬升,但是扫描的时间会变长
redis-cli -h 127.0.0.1 -p 7001 --bigkeys -i 0.1

计算每个键值的字节数

memory usage key

4. 大key如何删除

普通命令

  • String : 一般用del,如果过于庞大使用unlink key 删除

  • hash: 使用hscan每次获取少量field-value,再使用hdel删除每个field

  • list: 使用ltrim渐进式逐步删除,直到全部删除完成

  • set: 使用sscan每次获取部分元素,在使用srem命令删除每个元素

  • zset:使用zscan每次获取部分元素,在使用zremrangebyrank命令删除每个元素

5. BigKey生产调优

  • 分割BigKey:将一个大的key分割成多个小的key,例如将一个大的hash分割成多个小的hash。

  • 清理BigKey :对于不再需要的BigKey,可以直接删除。在Redis 4.0及以上版本,可以使用UNLINK命令异步删除key,避免阻塞。

  • 监控内存:设置内存使用率的监控阈值,提前发现潜在的BigKey问题。

  • 定期清理失效数据:对于存储大量数据的key,定期清理过期或无效数据。

  • 使用合适的数据结构:避免不必要的复杂数据结构,或者使用更高效的数据结构来减少内存占用

redis.conf配置文件 LAZY FREEING相关说明

阻塞和非阻塞删除命令

优化配置

lazyfree-lazy-eviction:当 redis 内存达到阈值 maxmemory 时,将执行内存淘汰
lazyfree-lazy-expire:当设置了过期 key 的过期时间到了,将删除 key
lazyfree-lazy-server-del:这种主要用户提交 del 删除指令
replica-lazy-flush:主要用于复制过程中,全量同步的场景,从节点需要删除整个 db
lazyfree-lazy-user-del:修改del命令的默认行为,使之与unlink命令一样

在处理BigKey时,应该尽量避免在主节点上进行大规模的扫描或删除操作,以免影响线上服务。可以考虑在从节点上进行这些操作,或者在业务低峰期进行。

6.最后

谢谢大家,请大家多多支持!

相关推荐
huangkj-henan2 分钟前
DA217应用笔记
笔记
Young_202202024 分钟前
学习笔记——KMP
笔记·学习
Leo.yuan17 分钟前
数据量大Excel卡顿严重?选对报表工具提高10倍效率
数据库·数据分析·数据可视化·powerbi
Runing_WoNiu26 分钟前
MySQL与Oracle对比及区别
数据库·mysql·oracle
sam-12329 分钟前
k8s上部署redis高可用集群
redis·docker·k8s
秀儿还能再秀36 分钟前
机器学习——简单线性回归、逻辑回归
笔记·python·学习·机器学习
WCF向光而行41 分钟前
Getting accurate time estimates from your tea(从您的团队获得准确的时间估计)
笔记·学习
天道有情战天下1 小时前
mysql锁机制详解
数据库·mysql
看山还是山,看水还是。1 小时前
Redis 配置
运维·数据库·redis·安全·缓存·测试覆盖率
谷新龙0011 小时前
Redis运行时的10大重要指标
数据库·redis·缓存