目录
1 五种基本数据对象
2 数据结构对象分析
Redis中的每个对象都由一个redisObject结构表示,该结构中保存数据相关的三个属性分别是:type、encoding、ptr。
redis.h
typedef struct redisObject {
//类型
unsigned type:4;
unsigned notused:2;
//编码
unsigned encoding:4;
unsigned lru:22;
//引用计数
int refcount;
//指向底层实现数据结构的指针
void *ptr;
} robj;
2.1 类型
对象的type属性记录了对象的类型,这个属性的值可以是表2-1列出对的常量中的一个。
对象 | 对象type属性的值 | TYPE命令的输出 |
字符串对象 | REDIS_STRING | string |
列表对象 | REDIS_LIST | list |
哈希对象 | REDIS_HASH | hash |
集合对象 | REDIS_SET | set |
有序集合对象 | REDIS_ZSET | zset |
TYPE命令的实现方式也与此类似,当我们对一个数据库键执行TYPE命令时,命令返回的结果为数据库键对应的值对象类型,而不是键对象类型:
# 键为字符串对象,值为字符串对象
127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> TYPE msg
string
# 键为字符串对象,值为列表对象
127.0.0.1:6379> RPUSH numbers 1 3 5
(integer) 3
127.0.0.1:6379> TYPE numbers
list
# 键为字符串对象,值为哈希对象
127.0.0.1:6379> HMSET profile name Tome age 25 career Programmer
OK
127.0.0.1:6379> TYPE profile
hash
# 键为字符串对象,值为集合对象
127.0.0.1:6379> SADD fruits apple banana cherry
(integer) 3
127.0.0.1:6379> TYPE fruits
set
# 键为字符串对象,值为有序集合对象
127.0.0.1:6379> ZADD price 8.5 apple 5.0 banana 6.0 cherry
(integer) 3
127.0.0.1:6379> TYPE price
zset
2.2 编码与底层实现
对象的ptr指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding属性决定。encoding属性记录了对象使用的编码,也即是说这个对象使用了什么数据结构作为对象的底层实现,这个属性的值可以是表2-2列出的常量的其中一个。
对象所使用的底层数据结构 | 编码常量 | OBJECT ENCODING命令输出 |
整数 | REDIS_ENCODING_INT | int |
embstr编码的简单动态字符串(SDS) | REDIS_ENCODING_EMBSTR | embstr |
简单动态字符串 | REDIS_ENCODING_RAW | raw |
字典 | REDIS_ENCODING_HT | hashtable |
双端链表 | REDIS_ENCODING_LINKEDLIST | linkedlist |
压缩列表 | REDIS_ENCODING_ZIPLIST | ziplist |
整数集合 | REDIS_ENCODING_INTSET | intset |
跳跃表和字典 | REDIS_ENCODING_SKIPLIST | skiplist |
使用OBJECT ENCODING命令可以查看一个数据库键的值对象的编码:
127.0.0.1:6379> SET msg "hello wrold"
OK
127.0.0.1:6379> OBJECT ENCODING msg
"embstr"
127.0.0.1:6379> SADD numbers 1 3 5
(integer) 3
127.0.0.1:6379> OBJECT ENCODING numbers
"intset"
127.0.0.1:6379> SADD numbers "seven"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING numbers
"hashtable"
每种类型的对象都至少使用了两种不同的编码,表2-3列出了每种类型的对象可以使用的编码:
类型 | 编码 | 对象 |
REDIS_STRING | REDIS_ENCODING_INT | 使用整数值实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用embstr编码的简单动态字符串实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_RAW | 使用简单动态字符串实现的字符串对象 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的列表对象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用双端链表实现的列表对象 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的哈希对象 |
REDIS_HASH | REDIS_ENCODING_HT | 使用字典实现的哈希对象 |
REDIS_SET | REDIS_ENCODING_INTSET | 使用整数集合实现的集合对象 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典实现的集合对象 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的有序集合对象 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳跃表和字典实现的有序集合对象 |
2.3 编码转换
(1)字符串对象
- 对于int编码的字符串对象来说,如果我们向对象执行了一些命令,使得对象保存的不再是整数值,而是一个字符串值,那么字符串对象将从int变为raw。
- 对embstr编码的字符串对象执行任何修改命令时,程序先将对象的编码从embstr转换成raw,然后再执行修改命令。
(2)列表对象
当列表对象可以同时满足以下两个条件时,列表对象使用ziplist编码:
- 列表对象保存的所有字符串元素的长度都小于64字节
- 列表对象保存的元素数量小于512个
(3)哈希对象
当哈希对象可以同时满足以下两个条件时,哈希对象使用ziplist编码:
- 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节
- 哈希对象保存的键值对数量小于512个
(4)集合对象
当集合对象可以同时满足以下两个条件时,对象使用intset编码:
- 集合对象保存的所有元素都是整数值
- 集合对象保存的元素数量不超过512个
(5)有序集合
当有序集合对象可以同时满足以下条件时,对象使用ziplist编码:
- 有序集合保存的元素数量小于128个
- 有序集合保存的所有元素的长度小于64字节
参考:
1、redis设计与实现(第二版)