Redis学习3——数据结构

数据结构

查看键的内部编码方式:object encoding key

Redis的键值都使用redisObject结构体保存,redisObject的结构:

    typedef struct redisObject {
        unsigned type:4;
        unsigned notused:2;    /* Not used */
        unsigned encoding:4;
        unsigned lru:22;       /* lru time (relative to server.lruclock) */
        int refcount;
        void *ptr;
    } ;

其中
refcount:键值被引用数量

type字:键值的数据类型:

        define REDIS_STRING 0
        define REDIS_LIST 1
        define REDIS_SET 2
        define REDIS_ZSET 3
        define REDIS_HASH 4

encoding:键值的内部编码方式

        define REDIS_ENCODING_RAW 0    /* Raw representation */
        define REDIS_ENCODING_INT 1    /* Encoded as integer */
        define REDIS_ENCODING_HT 2     /* Encoded as hash table */
        define REDIS_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
        define REDIS_ENCODING_LINKEDLIST/* Encoded as regular linked list */
        define REDIS_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
        define REDIS_ENCODING_INTSET 6  /* Encoded as intset */
        define REDIS_ENCODING_SKIPLIST 7  /* Encoded as skiplist */

每种数据类型都采用两种编码方式之一来存储

针对每种数据类型分别介绍其内部编码规则及优化方式:

一、字符串类型
Redis使用一个sdshdr类型的变量来存储字符串,redisObject的ptr字段指向的是该变量的地址。

        struct sdshdr {
            int len;
            int free;
            char buf[];
        };

len:字符串的长度
free:buf中的剩余空间
buf:字符串的内容
执行SET key foobar时,存储键值需要占用的空间是sizeof(redisObject) +sizeof(sdshdr) + strlen(“foobar”) = 30字节。
在这里插入图片描述

当键值内容可以用整数表示,Redis会将键值转换成long类型存储。如SET key 123456,实际占用的空间是sizeof(redisObject) = 16字节。

[插图]

Redis启动后会预先建立10000个分别存储从0到9999这些数字的redisObject类型变量作为共享对象,如果要设置的字符串键值在这10000个数字内(如SET key1123)则可以直接引用共享对象而不用再建立一个redisObject了,也就是说存储键值占用的空间是0字节。

提示:当通过配置文件参数maxmemory设置了Redis可用的最大空间大小时,Redis不会使用共享对象,因为每一个键值都需要使用一个redisObject来记录其LRU信息。

二、散列类型
配置

        hash-max-ziplist-entries 512
        hash-max-ziplist-value 64

当散列类型键的字段个数<hash-max-ziplist-entries&&每个字段名和字段值的长度都<hash-max-ziplist-value(单位为字节), Redis会使用REDIS_ ENCODING_ZIPLIST来存储该键,否则就会使用REDIS_ENCODING_HT。

转换时机
当键值变更后Redis都会根据条件判断是否需要转换。

REDIS_ENCODING_HT
编码为散列表,时间复杂度O(1),其字段和字段值都是使用redisObject存储(可使用字符串类型键值的优化)。

备注:Redis的键名没有使用redisObject存储,因为绝大多数情况下键名都不会是纯数字。

REDIS_ENCODING_ZIPLIST
编码类型更紧凑,牺牲部分读取性能以换取极高的空间利用率,适合在元素较少时使用。
在这里插入图片描述

zlbytes:表示整个结构占用的空间(uint32_t类型)
zltail:最后一个元素的偏移(uint32_t类型),使得程序可以直接定位到尾部元素而无需遍历整个结构,执行从尾部弹出(对列表类型而言)等操作时速度更快
zllen:元素的数量(uint16_t类型)
zlend:一个单字节标识,标记结构的末尾,值永远是255

每个元素由4个部分组成。
1.前一个元素的大小:以实现倒序查找,当前一个元素<254字节时,占用1个字节,否则占用5个字节。
2,3.元素的编码类型和元素的大小
当元素<=63个字节,元素的编码类型是ZIP_STR_06B(即0<<6),同时第三个部分用6个二进制位来记录元素的长度,
第二、三个部分总占用空间是1字节。
当元素>63&&元素<=16383字节时,第二、三个部分总占用空间是2字节
当元素>16383字节时,第二、三个部分总占用空间是5字节。
4.元素的实际内容:如果元素可以转换成数字,Redis会使用相应的数字类型来存储以节省空间,并且元素的编码类型和大小来使用数字的类型(int16_t、int32_t等)。

使用REDIS_ENCODING_ZIPLIST编码存储散列类型时元素的排列方式是:元素1存储字段1,元素2存储字段值1,依次类推,如图4-8所示。
[插图]
在这里插入图片描述

需要执行HSET hkey foo anothervalue时Redis需要从头开始找到值为foo的元素(查找时每次都会跳过一个元素以保证只查找字段名),找到后删除其下一个元素,并将新值anothervalue插入删除和插入都需要移动后面的内存数据,而且查找操作也需要遍历才能完成,所以散列键中数据多时性能将很低,hash-max-ziplist-entries和hash-max-ziplist-value两个参数应设置小些。

三、列表类型

配置:

        list-max-ziplist-entries 512
        list-max-ziplist-value 64

REDIS_ENCODING_LINKEDLIST
双向链表,链表中的每个元素是用redisObject存储。
REDIS_ENCODING_ZIPLIST
支持倒序访问,采用此种编码方式时获取两端的数据依然较快。

四、集合类型

配置

	set-max-intset-entries参数指定值(默认是512)

REDIS_ENCODING_INTSET
以有序的方式存储元素,使得可以使用二分算法查找元素
编码存储结构体intset:

        typedef struct intset {
            uint32_t encoding;
            uint32_t length;
            int8_t contents[];
        } intset;

contents:集合中的元素值,根据encoding的不同,每个元素占用的字节大小不同。默认的encoding是INTSET_ENC_INT16(即2个字节)。

五、有序集合类型

配置:

        zset-max-ziplist-entries 128
        zset-max-ziplist-value 64

REDIS_ENCODING_SKIPLIST:
散列表和跳跃列表(skip list)
散列表用来存储(元素值->元素分数的映射)以实现O(1)时间复杂度的ZSCORE等命令。
跳跃表用来存储(元素的分数->元素值的映射)以实现排序的功能。

REDIS_ENCODING_ZIPLIST
编码时有序集合
存储的方式按照“元素1的值,元素1的分数,元素2的值,元素2的分数”的顺序排列,并且分数是有序的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值