我们都知道Redis是一种kv键值对存储数据的非关系型数据库,当一个key的value值过大时,就会出现BigKey的问题,最直接的影响就是会影响我们redis的性能和稳定,所以我们需要清除和排查BigKey
首先多大算大Key?
一般情况下:
- String 类型的 key 对应的value超过 10 MB。
- list、set、hash、zset等集合类型,集合元素个数超过 5000个、
其实在实际开发中,对于大Key的定义也不是固定的,根据业务场景做出不同的判断
BigKey一般是如何产生的
在 各种不同的场景下都可能会出现BigKey问题,一般都是程序设计不当,对数据规模计划不清导致的
1、社交类:粉丝列表,逐步递增或者粉丝太多
2、统计类:如果按天存储某项功能或网站的用户集合,除非没几个人用,否则必定是bigkey
3、缓存类:作为数据库数据的冗余存储
BigKey会造成什么危害?
1.内存空间不均匀
在集群模式下,BigKey的存在会导致内存空间不均匀,这样不利于集群对内存的统一管理,无法做到负载均衡,并且集群的迁移也会十分困难
2.超时阻塞
由于Redis在命令串行执行时采用单线程,这也导致了操作BigKey操作会十分耗时,造成阻塞
3.网路阻塞
bigkey 也就意味着每次获取要产生的网络流量较大。假设一个 bigkey 为 1MB,客户端每秒访问量为 1000,那么每秒产生 1000MB 的流量,对于普通的千兆网卡(按照字节算是 128MB/s)的服务器来说简直是灭顶之灾。
4.阻塞删除
有个 bigkey,对它设置了过期时间,当它过期后会被删除,如果使用 Redis 4.0 之前的版本,过期 key 是异步删除,就会存在阻塞 redis 的可能性,而且这个过期删除不会从慢查询发现(因为这个删除不是客户端产生的,是内部循环事件)。
如何查找BigKey
1.通过bigkeys命令
优点
给出每种数据结构Top 1 bigkey,同时给出每种数据类型的键值个数+平均大小
不足
想查询大于10kb的所有key,--bigkeys参数就无能为力了,需要用到memory usage来计算每个键值的字节数
2.MEMORY USAGE key
如何优雅的删除BigKey
SCAN命令
特点:
SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
SCAN 返回一个包含两个元素的数组,
第一个元素是用于进行下一次迭代的新游标,
第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。如果新游标返回零表示迭代已结束。
SCAN的遍历顺序
非常特别,它不是从第一维数组的第零位一直遍历到末尾,而是采用了高位进位加法来遍历。之所以使用这样特殊的方式进行遍历,是考虑到字典的扩容和缩容时避免槽位的遍历重复和遗漏。
String类型:
一般直接使用DEL,如果是BigKey使用unlink进行异步删除
DEL key [key ...]
del命令会直接删除指定的键以及与之相关联的值。如果键不存在,则不执行任何操作。del命令不会释放已经分配的内存,因此如果有需要释放内存的场景,需要使用Redis提供的其他命令。
del命令是一种同步命令,即它会阻塞客户端,直到所有指定的键都被删除为止。在删除大量键的情况下,del命令可能会导致Redis服务器阻塞一段时间。因此,在删除大量键时,应该考虑使用异步删除方式,以避免阻塞客户端。
UNLINK key [key ...]
其中,key是要删除的键名。可以指定多个键名,删除多个键。如果指定的键不存在,则会被忽略。
与del命令不同的是,unlink命令会异步地删除指定的键以及与之相关联的值。即,它会将要删除的键添加到一个待删除的列表中,并立即返回,不会阻塞客户端。Redis服务器会在后台异步地删除待删除列表中的键。
使用unlink命令的好处是可以减少删除操作的阻塞时间。在删除大量键的情况下,unlink命令可以使Redis服务器更快地响应客户端请求。
Hash类型:
使用hscan每次获取少量filed-value,在使用hdel删除每一个filed
List类型:
使用ltrim渐进式逐步删除
Set类型:
使用sscan每次获取部分元素,再用srem删除每个元素
Zset类型:
使用zscan每次获取部分元素,再使用ZREMRANGEBYRANK删除每个元素
BIGKEY生产调优
lazyfree-lazy-server-del
针对有些指令在处理已存在的键时,会带有一个隐式的DEL键的操作。如rename命令,当目标键已存在,redis会先删除目标键,如果这些目标键是一个big key,那就会引入阻塞删除的性能问题。 此参数设置就是解决这类问题,建议可开启。
slave-lazy-flush
针对slave进行全量数据同步,slave在加载master的RDB文件前,会运行flushall来清理自己的数据场景,
参数设置决定是否采用异常flush机制。如果内存变动不大,建议可开启。可减少全量同步耗时,从而减少主库因输出缓冲区爆涨引起的内存使用增长。
后台删除之lazyfree机制
为了解决redis使用del命令删除大体积的key,或者使用flushdb、flushall删除数据库时,造成redis阻塞的情况,在redis 4.0引入了lazyfree机制,可将删除操作放在后台,让后台子线程(bio)执行,避免主线程阻塞。
生产上如何限制keys*/flushdb/flushall等危险命令?
通过配置设置禁用这些命令或者替换这些命令