bigkey

作者: HRADPX | 来源:发表于2019-07-07 19:53 被阅读0次

      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开发与运维》,如发现错误,请指正!

    相关文章

      网友评论

          本文标题:bigkey

          本文链接:https://www.haomeiwen.com/subject/oflihctx.html