bigkey是指key对应的value所占的内存空间比较大。按照数据结构细分,一般分为字符串类型bigkey和非字符串类型bigkey。
(1) 字符串类型:一般认为超过10KB就是bigkey。
(2) 非字符串类型:哈希、列表、集合、有序集合,体现在元素个数过多。
1 bigkey的危害
(1) 内存使用不均匀:例如在Redis集群中,bigkey会造成节点的内存空间使用不均匀。
(2) 超时阻塞:由于Redis单线程的特性,操作bigkey比较耗时,也就意味着阻塞Redis的可能性增大。
(3) 网络拥塞:每次获取bigkey产生的网络流量比较大,假设一个bigkey为1MB,每秒访问量为1000,那么每秒产生1000MB的流量。
2 发现bigkey
redis-cli --bigkeys可以命令统计bigkey的分布。
判断一个key是否是bigkey,只需执行debug object key查看serializedlength属性即可,它表示key对应的value序列化之后的字节数。
例如如果执行以下命令:
127.0.0.1:6379> debug object msg
Value at:000007F51306AEB0 refcount:1 encoding:raw serializedlength:31 lru:221580
4 lru_seconds_idle:10
可以发现serializedlength=31 字节,encoding是embstr,也就是字符串类型,可以通过strlen看以下字符串的字节数为1675个字节。
127.0.0.1:6379> strlen msg
(integer) 1675
serializedlength不代表真是的字符大小,它返回对象使用RDB编码序列化后的长度,值偏小。但是对于排查bigkey具有一定的辅助作用,因为不是每一种数据结构都有类似strlen的命令,如列表类型就没有strlen命令。
127.0.0.1:6379> lpush databases mysql oracle redis
(integer) 3
127.0.0.1:6379> strlen databases
(error) WRONGTYPE Operation against a key holding the wrong kind of value
在实际生产环境中,发现bigkey的两种方式:
(1) 被动收集:所谓被动收集就是等到出现了问题再去分析原因,如命令的慢查询或网卡跑满的情况,通过分析找到可能的原因是bigkey,这种方式不推荐使用。建议修改Redis客户端,当抛出异常打印所操作的key,方便排查bigkey。
(2) 主动收集:scan + debug object的命令,如果怀疑存在bigkey,可以使用scan命令渐进的扫描出所有的key,分别计算每个key的serializedlength,找到对应的bigkey进行相应的处理和报警,这种方式比较推荐。
SCAN 命令:用于迭代当前数据库中的数据库键。跟keys命令返回全部的数据库键不同,它每次执行都只会返回少量元素,所以可以用于生产环境。
SCAN 命令是一个基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
127.0.0.1:6379> scan 0
1) "13"
2) 1) "h"
2) "e"
3) "n"
4) "f"
5) "d"
6) "s"
7) "i"
8) "msg"
9) "k"
10) "databases"
127.0.0.1:6379> scan 13
1) "0"
2) 1) "r"
2) "t"
3) "message"
4) "m"
5) "j"
6) "l"
scan 0:第一次迭代使用 0 作为游标, 表示开始一次新的迭代。
第二次迭代使用的是第一次迭代时返回的游标, 也即是命令回复第一个元素的值 —— 13
在第二次调用SCAN命令时,命令返回了游标 0,这表示迭代已经结束, 整个数据集(collection)已经被完整遍历过了。
3 删除bigkey
使用del命令删除bigkey通常来说会阻塞Redis服务器,在生产环境中要尽量避免。
当bigkey对应的value越来越大,删除的时间也会随着增加。除了string类型删除时一般不产生阻塞,其他四种数据结构的删除都有可能产生阻塞。
删除bigkey要使用渐进式遍历的方式,利用sscan、hscan、zscan命令将若干个键拿出来。
实际中如何避免bigkey:
(1) 在数据结构的选择和设计应合理,如出现了bigkey,考虑可不可以优化(例如拆分数据结构)尽量让bigkey消失在业务中。
(2) 如果bigkey不可避免,也要考虑是不是每次都要将所有的元素都取出来,有时仅仅只需要hmget,而不是hgetall。
(3) Redis 4.0支持lazy delete free模式,删除bigkey不会阻塞Redis。
小结
(1) bigkey会造成数据倾斜,网络拥塞和超时阻塞,在实际环境中要重视bigkey。
(2) bigkey删除要使用渐进式遍历方式,防止出现Redis阻塞的情况。
(3) Redis 4.0支持lazy delete free,它不会阻塞Redis。
本文完
注:本文参考《Redis开发与运维》,如发现错误,请指正!
网友评论