redis对象
简介:redis用来存储键值对数据,而键值对数据在redis内部以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;
Type:对象的数据类型
- REDIS_STRING
- REDIS_LIST
- REDIS_HASH
- REDIS_SET
- REDIS_ZSET
Encoding:
- 对象的底层实现,与type对应。
- 不同类型对应不同函数集合,决定对象可以执行哪些函数。
- refcount:表示redis对象的引用数量,为零则回收。
lru:对象的最后一次被访问的时间戳。
- 字符串对象:type=REDIS_STRING
encoding=int,ptr存储long类型的地址
- 场景:保存的是整数,且处于long型的范围内。
encoding=raw,ptr存储SDS类型的地址
- 场景:保存的是字符串,且长度大于32字节。
encoding=embstr,ptr存储SDS类型的地址
- 场景:保存的是字符串,且长度小于等于32字节。
- 好处:采用一次申请同时分配redisobject和sds的地址。释放内存也只有一次。由于空间连续可以更好利用缓存优势。
- long double浮点数类型,也是用2,3来存储的,即采用sds字符串存储。当进行某些操作时会转换回double类型。
当执行某些命令时,int没有提供对应的函数实现,就会转换成raw。如append等。embstr类型是只读的,没有任何函数实现,执行任何修改命令都会转换成raw。
- 列表对象
encoding=ziplist,ptr存储压缩列表的地址
- 场景:同时满足列表对象存储的字符串元素长度都小于64字节,数量小于512个。
encoding=linkedlist,ptr存储双端链表的地址
- 场景:不满足上个场景。
- 哈希对象
- 场景:不满足上个场景。
encoding=ziplist,ptr存储压缩列表的地址
- 场景:存储的所有键值对的大小都小于64字节,数量小于512个。
encoding=hashtable,ptr存储字典的地址
- 场景:不满足上个场景。
- 集合对象
- 场景:不满足上个场景。
encoding=intset,ptr存储整数集合的地址
- 场景:元素都是整数且数量小于512个。
encoding=hashtable,ptr存储字典的地址
- 场景:不满足上个场景。
- 有序集合对象
- 场景:不满足上个场景。
encoding=ziplist,ptr存储压缩列表的地址
- 先存成员,紧接着存分值,按分值有序排列。
- 场景:存储的所有键值对的大小都小于64字节,数量小于128个。
- encoding=skiplist,ptr存储zset的地址
typedef struct zset{
zskiplist *zsl;
dict *dict;
}
- 场景:不满足上个场景。
- 其他:同时使用跳表和字典两种数据结构。字典的key是成员值,value是分值。好处是查分值o(1),范围型操作如zrank,时间复杂度太高。
多态命令
- del等命令是所有类型key都能执行,只是根据type及encoding不同,调用不同api。
- 类型特定命令:执行前检查type,如果满足判断encoding,根据编码不同,说明底层实现不同,然后调用不同底层数据结构的api。
对象共享
- redis在初始化服务器时,会创建从0到9999的所有整数值,当要使用整数字符串时,会共享整数池中的对象。
- 只会共享整数,不会共享字符串及其他更复杂的数据类型。因为要判断是否相等时间复杂度高。
对象的空转时长
- OBJECT IDLETIME命令会打印键的空转时长,通过当前时间减去lru得到。但该命令并不会更新lru。
- 当开启maxmemory选项时,空转时长较高的键会被释放。