Redis对象系统

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012050154/article/details/78647624

        在上一节学习Redis中的六种基础数据结构,但在Redis中并没有直接使用以上的数据结构实现键值对数据库,而是基于这些数据结构构建了一个对象系统:字符串对象(String)、列表对象(List)、哈希对象(Hash)、集合对象(Set)和有序集合对象(ZSet)。对于Redis数据库,键总是一个字符串对象,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象中的一种。

        使用对象系统的好处:

(1)在执行命令时,根据对象类型判断一个对象是否可以执行给定的命令;
(2)针对不同的使用场景,为对象设置多种不同的数据结构,从而优化对象在不同场景下的使用效率;
(3)基于对象引用计数技术实现内存的回收;
(4)通过引用计数技术实现对象的共享;

在Redis中每个对象都由一个redisObject结构表示:

/*
 * Redis 对象
 */
typedef struct redisObject {
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    // 引用计数
    int refcount;
    // 指向实际值的指针
    void *ptr;
} robj;

redisObject的类型字段:

redisObject的编码字段:

redisObject不同类型和编码的对象:



一、字符串对象(String)

        由上表可知,String对象的编码可以是int、embstr、raw。根据String对象保存值的不同,其使用的编码也不同:

        1、如果保存的是整数值,并且这个整数值可以用long类型来表示,则整数值会保存在字符串对象结构中的ptr属性里(void * 转换为long),并将字符串对象的编码设置为int。

        2、如果保存的是字符串值,并且这个字符串值长度小于等于39字节,则字符串对象使用embstr编码保存。

        3、如果保存的是字符串值,并且这个字符串值长度大于39字节,则字符串使用raw编码保存。

embstr与raw编码的区别是什么呢?

(a)创建embstr编码字符串内存分配1次,创建raw字符串内存分配2次;
(b)释放embstr编码的字符串调用内存释放函数1次,释放raw编码的字符串调用内存释放函数2次;
(c)embstr编码的字符串对象的所有数据都保存在一块连续的内存里面,可以更好的利用缓存带来的优势;

为什么是39个字节呢? 

embstr是一块连续的内存区域,由redisObject和sdshdr组成。其中redisObject占16个字节,当buf内的字符串长度是39时,sdshdr的大小为8+39+1=48,那一个字节是'\0'。加起来刚好64。(更详细的讲解可以参见知乎@lhcpig的解答

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;
struct sdshdr {
    unsigned int len;
    unsigned int free;
    char buf[];
};


Window环境下,在本地启动redis-server.exe,然后另启动一个redis-cli.exe。对String对象的操作如下:



二、列表对象(List)

        列表对象的编码可以是ziplist或者linkedlist。ziplist使用压缩列表作为底层实现,linkedlist使用双端链表作为底层实现。根据列表中存放的值不同,编码也有所不同:

        当列表对象所保存的所有字符串元素长度都小于64字节,并且元素数量小于512个,列表使用ziplist编码。不满足这两个条件的列表对象需要使用linkedlist编码。




三、哈希对象(Hash)

        哈希对象的编码可以是ziplist或者是hashtable。ziplist底层使用压缩列表实现,而hashtable底层使用字典实现。根据哈希对象存放的值不同,所使用的编码也不同:

        当哈希对象保存的所有键值对的键和值的字符串长度都小于64字节,并且键值对数量小于512个,哈希对象使用ziplist编码。不满足以上两个条件的哈希对象使用hashtable编码。




四、集合对象(Set)

        集合对象的编码可以是intset或者hashtable。intset底层使用的是整数集合实现,hashtable底层使用字典实现。根据集合对象存放的值不同,集合对象所使用的编码也不相同:

        当集合对象保存的所有元素都是整数值,并且对象保存的元素数量不超过512个,集合对象使用intset编码。不满足以上条件的使用hashtable编码。




五、有序集合对象(ZSet)

        有序集合的编码可以是ziplist或者skiplist。ziplist底层是用压缩列表实现,skiplist使用zset结构作为底层实现。根据有序集合存放的值不同,对象的编码也不同:

        有序集合保存的元素数量小于128个,并且所有元素成员长度都小于64个字节时,有序集合对象使用ziplist编码。不满足以上两个条件的采用skiplist编码。




参考文献

1、http://www.redis.net.cn/tutorial/3506.html

2、《Redis设计与实现》第二版---黄健宏

3、https://github.com/xingzhexiaozhu/redis-3.0-annotated

4、http://www.yiibai.com/redis/redis_strings.html

猜你喜欢

转载自blog.csdn.net/u012050154/article/details/78647624