Redis中的每个对象都由一个redisObject
结构表示,该结构中和保存数据有关的三个属性分别是type
、encoding
和ptr
:
typedef struct redisObject {
unsigned type:4; // 类型
unsigned encoding:4;// 编码
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;// 指向底层实现数据结构的指针
} robj;
1. 类型
Redis一共有5种类型,其中键值总是一个字符串对象,而值可以是5中类型中的任意一种。可以通过TYPE命令来查看键对应的值的类型
# 键为字符串对象,值为字符串对象
redis> SET msg "hello world"
OK
redis> TYPE msg
string
# 键为字符串对象,值为列表对象
redis> RPUSH numbers 1 3 5
(integer)6
redis> TYPE numbers
list
不同类型值对象的TYPE命令输出
对象类型 | 对象type属性值 | TYPE命令的输出 |
---|---|---|
字符串 | REDIS_STRING |
"string" |
列表 | REDIS_LIST |
"list" |
哈希 | REDIS_HASH |
"hash" |
集合 | REDIS_SET |
"set" |
有序集合 | REDIS_ZSET |
"zset" |
2. 编码
对象的ptr
指针指向对象的底层实现数据结构,而这些数据结构由对象的encoding
属性决定
redis> SET msg "hello world"
OK
redis> OBJECT ENCODING msg
"embstr" // msg为embstr类型
redis> SET story "long long long long long long long ago ..."
OK
redis> OBJECT ENCODING msg
"raw" // msg从embstr类型变成raw类型
redis> SADD numbers 1 3 5
(integer)3
redis> OBJECT ENCODING numbers
"intset" // numbers为intset类型
redis> SADD numbers "seven"
(integer)1
redis> OBJECT ENCODING numbers
"hashtable" // numbers从intset类型变成hashtable类型
不同类型和编码的对象
类型 | 编码常量 | 底层数据结构 |
---|---|---|
REDIS_STRING |
REDIS_ENCODING_INT |
整数 |
REDIS_STRING |
REDIS_ENCODING_IEMBSTR |
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 |
跳跃表 |
OBJECT ENCODING对不同类型编码的输出
编码常量 | OBJECT ENCODING命令输出 |
---|---|
REDIS_ENCODING_INT |
"int" |
REDIS_ENCODING_IEMBSTR |
"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" |
3. 对象底层数据结构
在Redis中为了节省空间,对象的编码是会发生转化,底层的数据结构也会随着发生变化。
-
字符串对象编码的转换规则
- 如果一个字符串对象保存的是整数值,并且这个值可以用
long
类型来表示,那么字符串对象会将整数值保存在对象结构ptr
属性里面,并将字符串对象的属性设置为int
- 如果字符串对象保存的是一个字符串值,并且长度小于
39
字节,那么字符串对象将使用embstr
编码 - 对于
int
编码的字符串对象来说,如果将值修改成字符串,那么字符串对象的编码将从int
变为raw
- 对于
embstr
编码的字符串对象来说,如果字符串的长度大于39
字节,那么字符串对象的编码将从embstr
变为raw
- 如果一个字符串对象保存的是整数值,并且这个值可以用
-
列表对象编码的转换规则
- 当列表对象保存的所有字符串元素的长度都小于
64
字节,并且保存的元素数量小于512
个,对象将使用ziplist
编码 - 如果对象不满足
ziplist
编码的条件,对象将使用linkedlist
编码
- 当列表对象保存的所有字符串元素的长度都小于
-
哈希对象编码的转换规则
- 当哈希对象保存的所有键和值的字符串长度都小于
64
字节,并且键值对数量小于512
个,对象将使用ziplist
编码 - 如果对象不满足
ziplist
编码的条件,对象将使用hashtable
编码
- 当哈希对象保存的所有键和值的字符串长度都小于
-
集合对象编码的转换规则
- 当集合对象保存的所有元素都是整数值,并且元素数量小于
512
个,对象将使用inset
编码 - 如果对象不满足
inset
编码的条件,对象将使用hashtable
编码
- 当集合对象保存的所有元素都是整数值,并且元素数量小于
-
有序集合对象编码的转换规则
- 当集合对象中保存的元素数量小于
128
个,并且所有元素成员的长度都小于64
字节,对象将使用ziplist
编码 - 如果对象不满足
ziplist
编码的条件,对象将使用skiplist
编码
- 当集合对象中保存的元素数量小于
4. 对象类型检查、回收、共享和空转时长
-
服务器在执行某些命令之前,会先检查给定键的类型能否执行指定的命令,而检查一个键的类型就是检查键的值对象的类型
-
Redis的对象带有引用计数实现的内存回收机制,当一个对象不再被使用时,该对象锁占用的内存就会被自动释放
-
Redis会自动共享值为0~9999的字符串对象
-
每个对象会记录自己的最后一次被访问的时间,这个时间可以用于计算对象的空转时间。当回收算法为
volatile-lru
或者allkeys-lru
,那么当服务器占用的内存超过了maxmemory
选项所设置的上限时,空转时间较高的那部分键会被服务器优先释放,从而回收内存