阿里三面:Redis大key怎么处理?

阿里三面:Redis大key怎么处理? 一、什么是大key首先大key不是key很大而是key对应的value值很大,一般而言如果String类型值大于10KBHashSetZsetList类型的元素的个数大于5000个都可以称之为大key。二、大key的危害客户端超时等待由于Redis执行命令是单线程处理然后在操作大key时会比较耗时那么就会阻塞Redis从客户端这一视角来看就是很久很久都没有响应引发网络阻塞每次获取大key产生的流量较大如果一个key的大小是1MB每秒访问量为1000那么每秒会产生1000MB的流量这对于普通千兆网卡是灾难的阻塞工作线程如果使用del删除大key会阻塞工作线程这样就没有办法处理后续的命令内存分布不均匀集群模型在slot分片均匀的情况下会出现数据和查询倾斜情况部分有大key的Redis节点占用内存多QPS比较大三、定位大key1、redi-cli --bigkeys使用时注意事项最好在从节点上执行该命令或者在Redis实例业务压力的低峰阶段进行扫描查询因为key很多时会很慢不足之处这个方法只能返回每种类型中最大的那个bigkey无法得到大小排到前N位的bigkey对于集合类型来说这个方法只统计集合元素的多少而不是实际占用的内存量。因为一个集合中元素个数多并不一定占用内存就多2.使用SCAN命令查找大key使用SCAN命令对数据库进行扫描。然后用TYPE命令获取返回的每一个key的类型对于String类型可以直接使用STRLEN命令获取字符串长度也就是占用的内存空间字节数对于集合类型来说可以使用MEMORY USAGE命令查询有关键值对占用的内存空间基于redis的keys、scan删除ttl为-1的key3.使用RdbTools使用第三方开源工具可以解析Redis快照找到其中的大key四、删除大key1.分批次删除使用SCAN扫描key比如删除Hash先取100字段删除删除再取2.异步删除在Redis4.0版本开始可以采用异步删除法用unlink命令代替del删除这样Redis会将这个key放入到一个异步线程中进行删除这样不会阻塞主线程3.被动删除前面两种都是主动删除这一种是通过配置参数当认为需要删除的时候就删除了lazyfree-lazy-eviction表示当 Redis 运行内存超过 maxmeory 时是否开启 lazy free 机制删除azyfree-lazy-expire表示设置了过期时间的键值当过期之后是否开启 lazy free 机制删除lazyfree-lazy-server-del有些指令在处理已存在的键时会带有一个隐式的 del 键的操作比如 rename 命令当目标键已存在Redis 会先删除目标键如果这些目标键是一个 big key就会造成阻塞删除的问题此配置表示在这种场景中是否开启 lazy free 机制删除slave-lazy-flush针对 slave (从节点) 进行全量数据同步slave 在加载 master 的 RDB 文件前会运行 flushall 来清理自己的数据它表示此时是否开启 lazy free 机制删除。建议开启其中的 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-server-del 等配置这样就可以有效的提高主线程的执行效率五、如何避免大key1.对大key进行拆分将一个Big Key拆分为多个key-value这样的小Key并确保每个key的成员数量或者大小在合理范围内然后再进行存储通过get不同的key或者使用mget批量获取。2.对大key进行清理对Redis中的大Key进行清理从Redis中删除此类数据。Redis自4.0起提供了UNLINK命令该命令能够以非阻塞的方式缓慢逐步的清理传入的Key通过UNLINK你可以安全的删除大Key甚至特大Key3.监控Redis内存、网络带宽、超时等指标通过监控系统并设置合理的Redis内存报警阈值来提醒我们此时可能有大Key正在产生如Redis内存使用率超过70%Redis内存1小时内增长率超过20%等。4.压缩value使用序列化、压缩算法将key的大小控制在合理范围内但是需要注意序列化、反序列化都会带来一定的消耗。如果压缩后value还是很大那么可以进一步对key进行拆分。