学习目标:
- 学习redis对象编码类型、对象类型
- 掌握对象编码从一种编码类型向另一种类型转换需要的条件
Redis对象
Redis的每个对象都是使用redisObject表示
typedef struct redisObject {
//类型
unsigned type:4;
//编码
unsigned encoding:4;
//指向底层实现数据结构的指针
void *ptr;
// ...
} robj;
redis对象的底层数据结构实现由对象的Encoding属性决定
可以使用“object encoding [key]”命令查看键的值对应得编码
每种对象可以使用的编码如下表:
对象 | 编码 | 类型 |
---|---|---|
整数值实现的字符串对象 | REDIS_ENCOFING_INT | REDIS_STRING |
embstr编码的简单动态字符串实现的字符串对象 | REDIS_ENCODING_EMDSTR | REDIS_STRING |
简单动态字符串实现的字符串对象 | REDIS_ENCOFING_RAW | REDIS_ STREING |
压缩列表实现的字符串对象 | REDIS_ENCOFING_ZIPLIST | REDIS_LIST |
双端链表实现的列表对象 | REDIS_ENCOFING_LINKEDLIST | REDIS_LIST |
字典实现的哈希对象 | REDIS_ENCOFING_HT | REDIS_HASH |
整数集合实现的集合对象 | REDIS_ENCOFING_INTSET | REDIS_SET |
字典实现的集合对象 | REDIS_ENCOFING_HT | REDIS_HASH |
压缩列表实现的有序集合对象 | REDIS_ENCOFING_ZIPLIST | REDIS_ZSET |
跳跃表和字典实现的有序集合对象 | REDIS_ENCOFING_SKIPLIST | REDIS_ZSET |
String
编码类型 | 说明 | 推荐 |
---|---|---|
int | 字符串对象保存的是整数值,并且整数值可以用long类型表示 | |
raw | 字符串对象保存的是字符串值,并且字符串值长度大于32字节 | 字符串值长度小于10KB,过大的字符串长度会引起数据倾斜、热key、实例流量或者cpu性能被占满等问题。如果字符串对象是一个key,推荐长度不超过128字节 |
embtr | value是字符串,并且字符串长度小于等于32字节 |
emstr编码是专门用户保存短字符串的优化编码,和raw一样都使用redisObject和sdshdr来表示字符串对象,raw会调用两次内存分配存储函数分别创建redisObject和sdshdr,embstr一次性分配连续的空间存放redisObject和sdshdr
相比raw,embstr的连续内存空间在内存回收、释放和缓存优势
embstr编码创建的内存块结构:
编码转换:
int->raw:对string对象执行了一些命令,使得对象不再是整数,而是一个字符串
embst->raw:emstr编码对象是只读的,对embstr编码的对象做任何修改都会使得对象转换成raw
List
编码类型 | 说明 | 推荐 |
---|---|---|
ziplist | 列表对象保存的所有字符串长度都小于64字节,并且,列表保存的元素数量小于512个 | |
linkedlist | 当列表对象保存的符串长度不满足ziplist要求的时候会转换为linkedlist编码 |
编码转换:
ziplist->linkedlist:当列表对象保存的所有字符串长度都大于等于64字节,或者,列表保存的元素数量大于等于512个会转换为linkedlist编码
Hash
编码类型 | 说明 | 推荐 |
---|---|---|
ziplist | 保存同一键值对的两个节点挨在一起,键在前值在后 | |
hashtable | 每一个键值对都用字典键值对保存 | 包含子key的话,推荐不应该超过1000个子key,某些命令(例如hgetall)的时间复杂度与key中子key的数量相关,如果频繁执行时间复杂度为O(N)及以上的命令,key中的子key数量过多,容易引发慢请求、数据倾斜或热key问题 |
编码转换:
ziplist->hashtable:hash对象保存的键或值长度大于等于64字节,或者,hash对象保存键值对数量大于等于512的时候
Set
编码类型 | 说明 | 推荐 |
---|---|---|
intset | 使用整数集合作为底层实现 | 元素小于1w个,元素总大小不超过100MB,否则容易造成大key问题 |
hashtable | 字典的每个键都是一个字符串对象,每个字符串对象包含一个集合元素,字典的值都是null | 同intset |
编码转换:
intset->hashtable:对set对象执行了一些命令操作,使得set对象的值不都是整数值了,或者,inset集合对象保存的元素数量已经超过512个
ZSet
编码类型 | 说明 | 推荐 |
---|---|---|
ziplist | 每个集合元素用紧挨一起的两个节点保存,前一个节点保存元素成员,第二个节点保存分值,分支小的元素靠近表头,大的靠近表尾 | 元素小于1W个 ,元素总大小不超过100MB,否则容易造成大key问题 |
skiplist | 底层是zset结构,一个zset结构同时包含一个字典和一个跳跃表 |
//zset数据结构
typedef struct zset {
zskiplist *zsl;
dict *dict;
} zset;
编码转换:
ziplist->skiplist:有序结合保存的元素数量大于等于128个,或者,有序集合保存的元素存在成员长度大于等于64字节