redisobject详解

前面说到,Redis对象有5种类型;无论是哪种类型,Redis都不会直接存储,
而是通过redisObject对象进行存储。
  • redisObject对象非常重要,Redis对象的类型、内部编码、内存回收、共享对象等功能,都需要redisObject支持,下面将通过redisObject的结构来说明它是如何起作用的。
  • redisObject的定义如下(列出了与保存数据有关的三个属性):
    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的每个字段的含义和作用如下:
    (1)type
    type字段表示对象的类型,占4个比特;目前包括REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)。
    当我们执行type命令时,便是通过读取RedisObject的type字段获得对象的类型;如下图所示:

    2)encoding

        encoding表示对象的内部编码,占4个比特。
        对于redis支持的每种类型都至少有两种编码,对于字符串有int、embsre、row三种
        通过encoding属性,redis可以根据不同的使用场景来对对象使用不同的编码,大大提高的redis的灵活性和效率。

     

     以列表对象为例,有压缩列表和双端链表两种编码方式;如果列表中的元素较少,
    Redis倾向于使用压缩列表进行存储,因为压缩列表占用内存更少,而且比双端链表可以更快载入;当列表对象元素较多时,压缩列表就会转化为更适合存储大量元素的双端链表。3.2版本以后都采用quicklist, 是压缩链表和双端链表的结合。
    什么意思呢,比如,一个包含三个结点的quicklist,如果每个结点的ziplist又包含四个数据项,那么对外表现上,这个list就总共包含12个数据项。这样的设计,实际上是对于时间和空间的一种折中。
    linkedlist便于在表的两端进行push和pop操作,但是它的内存开销较大。首先,它的每个节点除了要保存数据之外还要额外保存两个指针;其次,双向链表的各个节点是单独的内存块,地址不连续,容易产生内存碎片,还容易造成抖动。
    ziplist由于是一整块连续的内存,存储效率很高,但不利于添加和删除操作,每次都会重新realloc,尤其是当ziplist很长的时候,一次realloc造成的开销特别的大,查询的开销也特别的大。

     

     

     

     

    raw简单动态字符串

    当value长度超过44位,value编码方式变为raw,底层数据结构为简单动态字符串(SDS)

     

     这里来一个redisObject的全类型图:

  •  

    (3)lru属性

    lru记录此对象最后一次访问的时间。

    当redis内存回收算法设置为volatile-lru或者allkeys-lru时候redis会优先释放最久没有被访问的数据。

    (4)refcount属性

    用于共享计数,类似于jvm的引用计数垃圾回收算法,当refcount为0时,表示没有其它对象引用,可以进行释放此对象。

    (5)ptr 指针属性

    ptr 指针是指向对象的底层实现数据结构(详细内容见下一节)。

     

     

     

     

posted on 2022-07-12 22:59  小破孩楼主  阅读(184)  评论(0编辑  收藏  举报