Redis 是一个基于内存中的数据结构存储系统,可以用作数据库、缓存和消息中间件。Redis 支持五种常见对象类型:字符串(String )、哈希(Hash )、列表(List )、集合(Set )以及有序集合(Zset ),我们在日常工作中也会经常使用它们。知其然,更要知其所以然,本文将会带你读懂这五种常见对象类型的底层数据结构。
本文主要内容参考自《Redis设计与实现》
对象类型和编码
Redis 使用对象来存储键和值的,在Redis 中,每个对象都由redisObject 结构表示。redisObject 结构主要包含三个属性:type 、encoding 和ptr 。
typedef struct redisObject {
// 类型
unsigned type:4;
// 编码
unsigned encoding:4;
// 底层数据结构的指针
void *ptr;
} robj;
其中type 属性记录了对象的类型,对于Redis 来说,键对象总是字符串类型,值对象可以是任意支持的类型。因此,当我们说Redis 键采用哪种对象类型的时候,指的是对应的值采用哪种对象类型。
类型常量 |
对象类型名称 |
REDIS_STRING |
字符串对象 |
REDIS_LIST |
列表对象 |
REDIS_HASH |
哈希对象 |
REDIS_SET |
集合对象 |
REDIS_ZSET |
有序集合对象 |
*ptr 属性指向了对象的底层数据结构,而这些数据结构由encoding 属性决定。
编码常量 |
编码对应的底层数据结构 |
REDIS_ENCODING_INT |
long类型的整数 |
REDIS_ENCODING_EMBSTR |
emstr编码的简单动态字符串 |
REDIS_ENCODING_RAW |
简单动态字符串 |
REDIS_ENCODING_HT |
字典 |
REDIS_ENCODING_LINKEDLIST |
双端链表 |
REDIS_ENCODING_ZIPLIST |
压缩列表 |
REDIS_ENCODING_INTSET |
整数集合 |
REDIS_ENCODING_SKIPLIST |
跳跃表和字典 |
之所以由encoding 属性来决定对象的底层数据结构,是为了实现同一对象类型,支持不同的底层实现。这样就能在不同场景下,使用不同的底层数据结构,进而极大提升Redis 的灵活性和效率。
底层数据结构后面会详细讲解,这里简单看一下即可。
字符串对象
字符串是我们日常工作中用得最多的对象类型,它对应的编码可以是int 、raw 和embstr 。字符串对象相关命令可参考:Redis命令-Strings。
如果一个字符串对象保存的是不超过long 类型的整数值,此时编码类型即为int ,其底层数据结构直接就是long 类型。例如执行set number 10086 ,就会创建int 编码的字符串对象作为number 键的值。

如果字符串对象保存的是一个长度大于39字节的字符串,此时编码类型即为raw ,其底层数据结构是简单动态字符串(SDS );如果长度小于等于39个字节,编码类型则为embstr ,底层数据结构就是embstr 编码SDS 。下面,我们详细理解下什么是简单动态字符串。
简单动态字符串
SDS定义
在Redis 中,使用sdshdr 数据结构表示SDS :
struct sdshdr {
// 字符串长度
int len;
// buf数组中未使用的字节数
int free;
// 字节数组,用于保存字符串
char buf[];
};
SDS 遵循了C字符串以空字符结尾的惯例,保存空字符的1字节不会计算在len 属性里面。例如,Redis 这个字符串在SDS 里面的数据可能是如下形式:

SDS与C字符串的区别
C语言使用长度为N+1 的字符数组来表示长度为N 的字符串,并且字符串的最后一个元素是空字符
|