Redis对象类型
目录
对象
Redis中的键和值都是由对象来表示,键的对象类型总是字符串,而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种。
对象结构体定义:
xxxxxxxxxx
typedef 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_INT
long
类型的整数REDIS_ENCODING_EMBSTR
embstr
编码的简单动态字符串REDIS_ENCODING_RAW
简单动态字符串 REDIS_ENCODING_HT
字典 REDIS_ENCODING_LINKEDLIST
双端链表 REDIS_ENCODING_ZIPLIST
压缩列表 REDIS_ENCODING_INTSET
整数集合 REDIS_ENCODING_SKIPLIST
跳跃表和字典
字符串对象
编码
字符串对象的编码可以是 int
、 raw
或者 embstr
。
int
xxxxxxxxxx
redis> SET number 10086
OK
redis> OBJECT ENCODING number
"int"
raw:使用数据结构SDS
xxxxxxxxxx
redis> SET story "Long, long, long ago there lived a king ..."
OK
redis> STRLEN story
(integer) 43
redis> OBJECT ENCODING story
"raw"
embstr:使用数据结构SDS
xxxxxxxxxx
redis> SET msg "hello"
OK
redis> 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
或者embst
r编码。
embstr
也可以被转成raw
编码
列表对象
编码
列表对象的编码可以是 ziplist
或者 linkedlist
。
xxxxxxxxxx
redis> RPUSH numbers 1 "three" 5
(integer) 3
ziplist:压缩列表数据结构
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
结构同时包含一个字典和一个跳跃表:xxxxxxxxxx
typedef 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设计与实现》