目录
2.1 可以通过type命令来查看对象的类型
1、概述
redis并没有使用sds、双向链表、字典、压缩列表、整数集合这些数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,主要的类型有:REDIS_STRING、REDIS_LIST、REDIS_SET、REDIS_ZSET、REDIS_HASH,每种对象至少会使用到一种上面介绍的数据结构。
通过这五中不同的对象,redis在执行命令之前,根据对象的类型判断是否支持指定的命令。还有另外一个好处是,我们可以正对不同场景,为对象使用不同的数据结构实现。
// 对象类型
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4
2、实现
每次我们在数据库中创建一个键值对的时候,我们至少会创建两个对象,一个对象用作key的对象,一个用作value的对象。
type(类型):记录了对象的类型
encoding(编码):对象所使用的数据结构
ptr(指针):指向实际数据结构的指针
/* The actual Redis Object */
/*
* Redis 对象
*/
#define REDIS_LRU_BITS 24
#define REDIS_LRU_CLOCK_MAX ((1<<REDIS_LRU_BITS)-1) /* Max value of obj->lru */
#define REDIS_LRU_CLOCK_RESOLUTION 1000 /* LRU clock resolution in ms */
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;
2.1 可以通过type命令来查看对象的类型
2.2 对象编码对应的底层数据结构
2.3 String字符串对象
字符串的encoding可以是int、raw、embstr.
如果一个字符串对象保存的是整数值,并且这个整数值可以用long表示,这个对象的编码为int。
如果一个字符串对象保存的是字符串,并且这个字符串长度大于32字节,那么字符串对象将使用SDS来保存这个字符串,这个对象的编码为raw。
如果一个字符串对象保存的是字符串,并且这个字符串长度小于32字节,那么字符串对象将使用SDS来保存这个字符串,这个对象的编码为embstr。embstr所需的内存分配次数从raw的两次降低为一次;释放内存也从raw的两次降低为一次;embstr的内存是连续的。
注意:修改一个key的value可能存在对象类型的转换。
2.4 列表对象
列表对象的encoding可以是ziplist或者linkedlist。
2.5 Hash 哈希对象
哈希对象的encoding可以是ziplist或者hashtable。
2.6 Set 集合对象
集合对象的encoding可以是intset或者hashtable。
2.7 ZSet 有序集合对象
有序集合对象的encoding可以是ziplist或者skiplist。
3、总结
- 创建一个键值对的时候,我们至少会创建两个对象,一个对象用作key的对象,一个用作value的对象。
- redis共有字符串、列表、哈希表、集合、有序集合五中类型的对象。
- redis对象系统通过引用计数器进行内存回收
- 对象记录了最后一次被访问时间,这个时间用于计算对象的空转时间。如果程序打开了maxmemory选项,并且服务器的回收内存算法为volatile-lru/allkeys-lru,当服务器占用内存超过maxmemory,空转时长比较高的那部分会优先被回收。