Redis对象类型
目录
对象
Redis中的键和值都是由对象来表示,键的对象类型总是字符串,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种。
对象结构体定义:
xxxxxxxxxxtypedef struct redisObject {    // 类型    unsigned type:4;    // 编码    unsigned encoding:4;    // 指向底层实现数据结构的指针    void *ptr;    // ...} robj;type 数据类型
type的取值如下:
类型常量 对象的名称 REDIS_STRING字符串对象 REDIS_LIST列表对象 REDIS_HASH哈希对象 REDIS_SET集合对象 REDIS_ZSET有序集合对象 encoding 数据编码
encoding决定了对象使用的底层数据结构,有如下取值:
REDIS_ENCODING_INTlong类型的整数REDIS_ENCODING_EMBSTRembstr编码的简单动态字符串REDIS_ENCODING_RAW简单动态字符串 REDIS_ENCODING_HT字典 REDIS_ENCODING_LINKEDLIST双端链表 REDIS_ENCODING_ZIPLIST压缩列表 REDIS_ENCODING_INTSET整数集合 REDIS_ENCODING_SKIPLIST跳跃表和字典 
字符串对象
编码
字符串对象的编码可以是 int 、 raw 或者 embstr 。
int
xxxxxxxxxxredis> SET number 10086OKredis> OBJECT ENCODING number"int"
raw:使用数据结构SDS
xxxxxxxxxxredis> SET story "Long, long, long ago there lived a king ..."OKredis> STRLEN story(integer) 43redis> OBJECT ENCODING story"raw"
embstr:使用数据结构SDS
xxxxxxxxxxredis> SET msg "hello"OKredis> OBJECT ENCODING msg"embstr"embstr是用来保存短字符串,使用embstr有以下好处:
embstr编码将创建字符串对象所需的内存分配次数从raw编码的两次降低为一次。- 释放 
embstr编码的字符串对象只需要调用一次内存释放函数, 而释放raw编码的字符串对象需要调用两次内存释放函数。 - 因为 
embstr编码的字符串对象的所有数据都保存在一块连续的内存里面, 所以这种编码的字符串对象比起raw编码的字符串对象能够更好地利用缓存带来的优势。 
字符串对象保存各类型值的编码方式
| 值 | 编码 | 
|---|---|
可以用 long 类型保存的整数。 | int | 
可以用 long double 类型保存的浮点数。 | embstr 或者 raw | 
字符串值, 或者因为长度太大而没办法用 long 类型表示的整数, 又或者因为长度太大而没办法用 long double 类型表示的浮点数。 | embstr 或者 raw | 
编码转换
int编码的字符串通过某种操作之后,比如末尾添加字符的操作,会被转换成raw或者embstr编码。
embstr也可以被转成raw编码
列表对象
编码
列表对象的编码可以是 ziplist 或者 linkedlist 。
xxxxxxxxxxredis> RPUSH numbers 1 "three" 5(integer) 3ziplist:压缩列表数据结构

linkedlist:双端链表数据结构

编码转换
当列表对象可以同时满足以下两个条件时, 列表对象使用 ziplist 编码:
- 列表对象保存的所有字符串元素的长度都小于 
64字节; - 列表对象保存的元素数量小于 
512个; 
不能满足这两个条件的列表对象需要使用 linkedlist 编码。
以上两个条件的上限值是可以修改的, 具体请看配置文件中关于
list-max-ziplist-value选项和list-max-ziplist-entries选项的说明。
哈希对象
编码
哈希对象的编码可以是 ziplist 或者 hashtable 。
ziplist 压缩列表数据结构

hashtable: 压缩表

编码转换
当哈希对象可以同时满足以下两个条件时, 哈希对象使用 ziplist 编码:
- 哈希对象保存的所有键值对的键和值的字符串长度都小于 
64字节; - 哈希对象保存的键值对数量小于 
512个; 
不能满足这两个条件的哈希对象需要使用 hashtable 编码。
这两个条件的上限值是可以修改的, 具体请看配置文件中关于
hash-max-ziplist-value选项和hash-max-ziplist-entries选项的说明。
集合对象
编码
集合对象的编码可以是 intset 或者 hashtable 。
inset:整数集合数据结构

hashtable:哈希表数据结构

编码转换
当集合对象可以同时满足以下两个条件时, 对象使用 intset 编码:
- 集合对象保存的所有元素都是整数值;
 - 集合对象保存的元素数量不超过 
512个; 
不能满足这两个条件的集合对象需要使用 hashtable 编码。
第二个条件的上限值是可以修改的, 具体请看配置文件中关于
set-max-intset-entries选项的说明。
有序集合对象
编码
有序集合的编码可以是 ziplist 或者 skiplist 。
ziplist 压缩列表


skiplist 基于跳表+字典
skiplist编码的有序集合对象使用zset结构作为底层实现, 一个zset结构同时包含一个字典和一个跳跃表:xxxxxxxxxxtypedef struct zset {zskiplist *zsl;dict *dict;} zset;通过这个字典, 程序可以用 O(1) 复杂度查找给定成员的分值。

编码转换
当有序集合对象可以同时满足以下两个条件时, 对象使用
ziplist编码:- 有序集合保存的元素数量小于 
128个; - 有序集合保存的所有元素成员的长度都小于 
64字节; 
不能满足以上两个条件的有序集合对象将使用
skiplist编码。以上两个条件的上限值是可以修改的, 具体请看配置文件中关于
zset-max-ziplist-entries选项和zset-max-ziplist-value选项的说明。- 有序集合保存的元素数量小于 
 
内存回收
采用引用计数
对象共享
Redis 只对包含整数值的字符串对象进行共享。
不共享包含字符串的对象的原因?验证共享对象和目标对象是否相同所需的复杂度高,需要O(n)的时间。所以从CPU资源的角度来看,不对字符串进行共享。
参考
- 书籍《Redis设计与实现》