【重学Redis】Redis 对象 redisObject

开课吧樵夫2021-12-31 14:47

  redisObject 结构体是在 server.h 文件中定义的,主要功能是用来保存键值对中的值。这个结构一共定义了 4 个元数据和一个指针。

【重学Redis】Redis 对象 redisObject

  server.h

typedef struct redisObject {
    //redisObject的数据类型,4个bits
    unsigned type:4;        //  4 bit, sting , hash
    //redisObject的编码类型,4个bits
    unsigned encoding:4;    //  4 bit
    //redisObject的LRU时间,LRU_BITS为24个bits
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). 
                            *    24 bit 
                            * */
    //redisObject的引用计数,4个字节
    int refcount;           // 4 byte
    //指向值的指针,8个字节
    void *ptr;              // 8 byte  总空间:  4 bit + 4 bit + 24 bit + 4 byte + 8 byte = 16 byte  
} robj;

  从代码中我们可以看到,在 type、encoding 和 lru 三个变量后面都有一个冒号,并紧跟着一个数值,表示该元数据占用的比特数。其中,type 和 encoding 分别占 4bits。而 lru 占用的比特数,是由 server.h 中的宏定义 LRU_BITS 决定的,它的默认值是 24bits

  server.h

#define LRU_BITS 24

  对于 type、encoding 和 lru 三个变量来说,它们的数据类型都是 unsigned。一个 unsigned 类型是 4 字节,但这三个变量,是分别占用了一个 unsigned 类型 4 字节中的 4bits、4bits 和 24bits。因此,相较于每个变量用 4 字节的int定义来说,使用位域定义方法可以让三个变量只用 4 字节,最后就能节省 8 字节的开销。

  type

  type表示redisObject存储的值的类型,包括 String、List、Hash 等。每种类型都有对应的值,比如说最大的Stream类型,对应的值为6.二进制为0110.那么type就是0110.4个bits就够用了

  数据类型

  server.h

//string类型
#define OBJ_STRING 0    /* String object. */
//list类型
#define OBJ_LIST 1      /* List object. */
//set类型
#define OBJ_SET 2       /* Set object. */
//Sorted set类型
#define OBJ_ZSET 3      /* Sorted set object. */
//Hash类型
#define OBJ_HASH 4      /* Hash object. */
//Module类型
//“模块”对象类型是一种特殊类型,表示对象是由Redis模块直接管理的
#define OBJ_MODULE 5    /* Module object. */
//Stream类型
#define OBJ_STREAM 6    /* Stream object. */

  当我们使用TYPE命令的时候,就会返回redisObject中type字段对应的类型

127.0.0.1:6379>SET keystr valstr
"OK"
127.0.0.1:6379>TYPE keystr
"string"

  注意:在redis中,key-value对中的键总是字符串类型的,只有值可以是多种类型中的一种,因此当我们称一个键为“字符串”时,是指这个键对应的value是字符串类型的。

  encoding

  encoding存储了值的编码格式,Redis支持的编码格式共有11种,每种都有对应的值,最大的为Stream对应的值10.二进制表示为1010.4bits就够用了

  编码格式

  server.h

//原始字符串RAW
#define OBJ_ENCODING_RAW 0     /* Raw representation */
//整数INT
#define OBJ_ENCODING_INT 1     /* Encoded as integer */
//哈希表HT
#define OBJ_ENCODING_HT 2      /* Encoded as hash table */
//压缩集合zipmap
#define OBJ_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
//双端链表LINKEDLIST
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
//压缩列表ZIPLIST
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
//整数集合INTSET
#define OBJ_ENCODING_INTSET 6  /* Encoded as intset */
//跳表SKIPLIST
#define OBJ_ENCODING_SKIPLIST 7  /* Encoded as skiplist */
//嵌入式字符串EMBSTR
#define OBJ_ENCODING_EMBSTR 8  /* Embedded sds string encoding */
//快速列表QUICKLIST
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
//stream编码
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks stream*/

  通过OBJECT encoding key命令可以查看key对应的value的编码,返回的就是redisObject中encoding 字段对应的类型

127.0.0.1:6379> OBJECT encoding keystr
"embstr"

  lru

  lru存储redisObject 的LRU时间(相对于全局LRU_时钟)或LFU数据

  当使用LRU淘汰策略时,存储最近一次访问(get,set)的时间戳,精度是秒,所以如果连续两次的访问的时间间隔小于 1 秒,那么这两次访问的时间戳就是一样的

  通过OBJECT IDLETIME key命令可以获取 key 距离上次访问的时间,也就是当前时间的时间戳减去lru存储的时间戳

127.0.0.1:6379> get keystr
"valstr"
127.0.0.1:6379> OBJECT IDLETIME keystr
(integer) 2

  refcount

  refcount 存储了redisObject 的引用计数,主要用于对象的引用计数和内存回收。

  refcount会随着对象的使用状态而变化:

  在创建一个新对象时,引用计数的值会被初始化为1;

  当对象被一个新程序使用时,它的引用计数值会被增加1;

  当对象不再被一个程序使用时,它的引用计数值会被减1;

  当对象的引用计数值变为0时,对象所占用的内存会被释放。

  命令 OBJECT REFCOUNT KEY可以查看指定 key 的引用计数值

127.0.0.1:6379> OBJECT REFCOUNT keystr
(integer) 1

  ptr

  指向值的指针,8个字节,指针通常来说就是指向实际数据的,但是当存储一个比较小的整数时,也有可能直接存储整数值,这样做是为了节省空间

  当我们存储一个比较长的字符串时,我们知道字符串时存储在SDS的结构里的,然后这个指针就指向这个SDS

  还记得我们上节课的dictEntry吗 ,在Redis中,dictEntry 的key是一个指针,指向存储“键”的SDS,而当v使用val(指针)存储的时候,val就指向redisObject

typedef struct dictEntry {
    // 键
    void *key;
    // 值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    // 下一个节点
    struct dictEntry *next;
} dictEntry;

  以上就是开课吧小编为大家整理发布的“【重学Redis】Redis 对象 redisObject”一文,更多相关内容尽在开课吧广场Java教程频道。

【重学Redis】Redis 对象 redisObject

免责声明:本站所提供的内容均来源于网友提供或网络搜集,由本站编辑整理,仅供个人研究、交流学习使用。如涉及版权问题,请联系本站管理员予以更改或删除。
有用
分享
全部评论快来秀出你的观点
登录 后可发表观点…
发表
暂无评论,快来抢沙发!
高并发编程训练营