简述
大家都知道,使用object encoding key
就能看出redis value的数据结构,比如raw、int、hash、ziplist等
,我一开始也以为redis key-value结构,value直接使用数据结构,但是如果是这样object encoding key
命令就说不通了。所以我再次看redis源码分析下😊。
redisObject
首先看redisObject,它在server.h下。
typedef struct redisObject {
/*类型*/
unsigned type:4;
/*编码*/
unsigned encoding:4;
/*对象最后一次被访问的时间*/
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). */
/*引用计数*/
int refcount;
/*指向底层实现数据结构的指针*/
void *ptr;
} robj;
可以看到,其实在Redis中创建一个key-value时,我们会至少创建两个对象,key和value。key和value其实都是redisObject类型,key的话,最终会存的是SDS类型,这里我们先看redisObject中的参数。
type
/* The actual Redis Object */
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
#define OBJ_MODULE 5 /* Module object. */
#define OBJ_STREAM 6 /* Stream object. */
含义:
类型 | 值 | 名称 |
---|---|---|
OBJ_STRING | 0 | 字符串对象 |
OBJ_LIST | 1 | 列表对象 |
OBJ_SET | 2 | 集合对象 |
OBJ_ZSET | 3 | 有序集合对象 |
OBJ_HASH | 4 | hash对象 |
OBJ_MODULE | 5 | RDB文件中用到的模块对象,不太了解 |
OBJ_STREAM | 6 | 流对象,不太了解 |
encoding
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
含义:
类型 | 值 | 名称 |
---|---|---|
OBJ_ENCODING_RAW | 0 | 简单动态字符串 |
OBJ_ENCODING_INT | 1 | 最大值为2的63次方-1 |
OBJ_ENCODING_HT | 2 | 字典 |
OBJ_ENCODING_ZIPMAP | 3 | 压缩字典 |
OBJ_ENCODING_LINKEDLIST | 4 | 双端链表,注释写着不再使用 |
OBJ_ENCODING_ZIPLIST | 5 | 压缩列表 |
OBJ_ENCODING_INTSET | 6 | 整数集合 |
OBJ_ENCODING_SKIPLIST | 7 | 跳跃表,不过也包含字典 |
OBJ_ENCODING_EMBSTR | 8 | 短的简单动态字符串 |
OBJ_ENCODING_QUICKLIST | 9 | 快速列表,是ziplist和linkedList的混合体 |
OBJ_ENCODING_STREAM | 10 | 流,不太了解 |
lru
Least Recently Used
,对象最后一次被访问的时间。
refcount
refcount
表示引用计数,由于C语言没有自动内存回收功能,所以Redis在对象中添加这个属性,如果refcount
为0的时候,可以进行垃圾回收。
ptr
指向对象的底层实现数据结构指针。
使用RedisObject的好处
- 能直接知道对象类型,在执行命令之前可以根据对象的类型来执行给定的命令。我们可以通过
type key
获取到数据结构类型;通过object encoding key
可以获取到存储的数据结构。 - 可以针对不同的使用场景,为不同的对象设置不同的实现,大大优化了内存和查询速度。比方说hash,数据量比较少,数据都比较小的时候会使用ziplist数据结构,大大减少内存占用,因为数据量小,zip查询速度也不会很慢;当数据量比较多,数据比较大的时候,会使用hashTable数据结构,虽然内存没ziplist占用少,但是查询时间复杂度为O(1)。
key对象类型
我上面也说了,key和value都使用了redisObject,那么key具体的数据结构是什么?带着疑问,我看了添加键值对的方法,具体在db.c下:
/* Add the key to the DB. It's up to the caller to increment the reference
* counter of the value if needed.
*
* The program is aborted if the key already exists. */
void dbAdd(redisDb *db, robj *key, robj *val) {
/*使用sds,简单动态字符串*/
sds copy = sdsdup(key->ptr);
int retval = dictAdd(db->dict, copy, val);
serverAssertWithInfo(NULL,key,retval == DICT_OK);
signalKeyAsReady(db, key, val->type);
if (server.cluster_enabled) slotToKeyAdd(key->ptr);
}
以上代码可以看出,每次存储key-value的时候,key都会使用sds(简单动态字符串)
来存。所以key是string类型,是固定的。
总结
今天介绍了redisObject,自己看了源码,和结合《redis设计与实现》对redisObject介绍总结的。网上的大部分文档没有对源码的解析,自己去看了遍,印象更加深刻。只要存疑,自己亲自去查看,而不是只关注别人发的文章,才更有收获!下次我会继续介绍type和encoding的几种类型。
评论区