• redis 各种数据结构的encoding实现


    redis 各种数据结构的encoding实现


    Redis type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合),但这些只是Redis对外的数据结构。

    • 实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,这样Redis会在合适的场景选择合适的内部编码。

    • 可以看到每种数据结构都有两种以上的内部编码实现,例如string数据结构就包含了raw、int和embstr三种内部编码。

    • 同时,有些内部编码可以作为多种外部数据结构的内部实现,例如ziplist就是hash、list和zset共有的内部编码。

    我们可以通过object encoding命令查询内部编码:
    127.0.0.1:6379> set set:1 hello
    OK
    127.0.0.1:6379> object encoding set:1
    "embstr"
    127.0.0.1:6379> hset user:1 name kebi
    (integer) 1
    127.0.0.1:6379> object encoding user:1
    "ziplist"
     

     

    可以看到键set:1对应值的内部编码是“embstr”,键user:1对应值的内部编码是“ziplist”。

    Redis这样设计有两个好处:

    1. 第一,可以改进内部编码,而对外的数据结构和命令没有影响,这样一旦开发开发出优秀的内部编码,无需改动外部数据结构和命令。

    2. 第二,多种内部编码实现可以在不同场景下发挥各自的优势。例如ziplist比较节省内存,但是在列表元素比较多的情况下,性能会有所下降,

    3. 这时候Redis会根据配置选项将列表类型的内部实现转换为linkedlist。

    下面会分别介绍5种数据结构的内部编码方式。

    1.字符串的内部编码

    字符串类型的内部编码有3种:

    int:8个字节的长整型。
    embstr:小于等于39个字节的字符串。
    raw:大于39个字节的字符串。

    • Redis会根据当前值的类型和长度决定使用内部编码实现。
    (1)整数类型示例如下:
    127.0.0.1:6379> set str 1234567 
    OK
    127.0.0.1:6379> object encoding str
    "int"
     
    (2)短字符串示例如下:
    127.0.0.1:6379> set str "hello world"
    OK
    127.0.0.1:6379> object encoding str
    "embstr"
     
    (3)长字符串示例如下:
    127.0.0.1:6379> set str "Tranquil,unbeatable to the outside. -- yangming"  #“凝聚于内,无敌于外。--王阳明”
    OK
    127.0.0.1:6379> object encoding str
    "raw"
     

     

    2.哈希的内部编码

    哈希类型的内部编码有两种:

    • ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)
          同时所有值都小于hash-max-ziplist-value配置(默认64个字节)时,Redis会使用ziplist作为哈希的内部实现
          ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀。

    • hashtable(哈希表):当哈希类型无法满足ziplist的条件时,Redis会使用hashtable作为哈希的内部实现。
          因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1)。

    • 下面演示哈希类型的内部编码,及相应的变化。
    (1)当field个数比较少且没有大的value时,内部编码为ziplist:
    127.0.0.1:6379> hmset user:2 name kebi age 26
    OK
    127.0.0.1:6379> object encoding user:2
    "ziplist"
     
    (2)当有value大于64个字节,内部编码会由ziplist变为hashtable:
    127.0.0.1:6379> hmset user:1 info "沐春风,惹一身红尘;望秋月,化半缕轻烟。顾盼间乾坤倒转,一霎时沧海桑田。方晓,弹指红颜老,刹那芳华逝。"
    127.0.0.1:6379> object encoding user:1
    "hashtable"
     
    (3)当field个数超过512,内部编码也会由ziplist变为hashtable:
    ...待插入内容...
     

     

    注意:当一个哈希的编码由ziplist变为hashtable的时候,即使在替换掉所有值,它一直都会是hashtable类型。

    3.列表的内部编码

    列表类型的内部编码有两种:

    ziplist(压缩列表):当哈希类型元素个数小于hash-max-ziplist-entries配置(默认512个)
        同时所有值都小于hash-max-ziplist-value配置(默认64个字节)时,Redis会使用ziplist作为哈希的内部实现。

    linkedlist(链表):当列表类型无法满足ziplist的条件时,Redis会使用linkedlist作为列表的内部实现。

    • 下面演示列表类型的内部编码,以及相应的变化:
    (1)当元素个数较少且没有大元素时,内部编码为ziplist:
    127.0.0.1:6379> rpush list:2 a b c
    (integer) 3
    127.0.0.1:6379> object encoding list:2
    "ziplist"
     
    (2)当元素个数超过512个,内部编码变为linkedlist:
    127.0.0.1:6379>lpush setkey 1 2 3 ... 513
    OK
    127.0.0.1:6379> object encoding listkey
    "linkedlist"
     
    (3)当某个元素超过64个字节,内部编码也会变为linkedlist:
    127.0.0.1:6379> rpush list:1 a b "我不再说话,不再思索,但无尽的爱从灵魂中升起,我将远行,走得很远,如同一个吉普塞人,穿过大自然——幸福得如有一位女子同行。"
    (integer) 6
    127.0.0.1:6379> object encoding list:1
    "linkedlist"
    
    - #只能升级,不能自动变回ziplist类型
     
    4.集合的内部编码

    集合类型的内部编码有两种:

    intset(整数集合):当集合中的元素都是整数且元素个数小于set-max-intset-entries配置(默认512个)时,
        Redis会选用intset来作为集合内部实现,从而减少内存的使用。

    hashtable(哈希表):当集合类型无法满足intset的条件时,Redis会使用hashtable作为集合的内部实现。

    • 下面用示例来说明:
    (1)当元素个数较少且都为整数时,内部编码为intset:
    127.0.0.1:6379> sadd setkey 2 3 4 5
    (integer) 4
    127.0.0.1:6379> object encoding setkey
    "intset"
     
    (2)当元素个数超过512个,内部编码变为hastable:
    127.0.0.1:6379>sadd setkey2 1 2 3 4 5 6 7...  511 512 513
    OK
    127.0.0.1:6379> object encoding setkey2
    "hashtable"
     
    (3)当某个元素不为整数时,内部编码也会变为hashtable:
    127.0.0.1:6379> sadd setkey3 a b c
    (integer) 3
    127.0.0.1:6379> object encoding setkey2
    "hashtable"
     
    5.有序集合的内部编码

    有序集合类型的内部编码有两种

    ziplist(压缩列表):当有序集合的元素个数小于zset-max-ziplist-entries配置(默认128个)
        同时每个元素的值小于zset-max-ziplist-value配置(默认64个字节)时,Redis会用ziplist来作为有序集合的内部实现,ziplist可以有效减少内存使用。

    skiplist(跳跃表):当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时zip的读写效率会下降。

    • 下面用示例来说明:
    (1)当元素个数较少且每个元素较小时,内部编码为ziplist:
    127.0.0.1:6379> zadd zsetkey 50 a 60 b 30 c
    (integer) 3
    127.0.0.1:6379> object encoding zsetkey
    "ziplist"
     
    (2)当元素个数超过128个,内部编码变为skiplist:
    ...待输入...
     
    (3)当某个元素大于64个字节时,内部编码也会变为skiplist:
    127.0.0.1:6379> zadd zsetkey 50 a 60 b 30 '闪烁的太阳已越过高傲的山峦,幽谷中的光点有若泡沫浮起。'
    (integer) 1
    127.0.0.1:6379> object encoding zsetkey
    "skiplist"
     

    ————————————————————————————————
    本文内容非本猿原创,只是在作者原文稍作修改。
    ————————————————————————————————
    原文链接:https://blog.csdn.net/clypm/article/details/52312937

     
  • 相关阅读:
    python 文件 笔记
    python 模块、包 笔记
    类、对象
    python 函数 笔记
    测试价值体现
    断舍离-笔记2
    Happy 2006 POJ
    Triangle War POJ
    Complete the sequence! POJ
    放苹果 POJ
  • 原文地址:https://www.cnblogs.com/brady-wang/p/13405244.html
Copyright © 2020-2023  润新知