Redis底层数据结构
Redis对象
typedef struct redisObject {
/*数据类型*/
unsigned type:4;
/*编码方式*/
unsigned encoding:4;
/*最后一次被访问的时间,保存了一个24位时间戳*/
unsigned lru:LRU_BITS;
/*记录了键值被引用的数量*/
int refcount;
/*指向底层数据结构的指针*/
void *ptr;
} robj
数据类型 type
值 | 代码 | 数据类型 | 最大值 | 备注 |
---|---|---|---|---|
0 | OBJ_STRING | string | 512 M | |
1 | OBJ_LIST | list | 232 - 1 个 | |
2 | OBJ_SET | set | 232 - 1 个 | 场景:好友集合,粉丝集合 |
3 | OBJ_ZSET | zset | 232 - 1 个 | 场景:排行榜 |
4 | OBJ_HASH | hash | 223 - 1 个 | |
5 | OBJ_MODULE | module | 模块 ( redis >= 4.0 ),加载外部模块进行功能性扩展 | |
6 | OBJ_STREAM | stream | 流 ( redis >= 5.0.0 ),支持多播的可持久化消息队列 |
备注:redis < 3.2 编码方式以“REDIS_”开头,不是“OBJ_”
编码方式 encoding
值 | 代码 | 备注 |
---|---|---|
0 | OBJ_ENCODING_RAW | 简单动态字符串 |
1 | OBJ_ENCODING_INT | 整数值 |
2 | OBJ_ENCODING_HT | 字典 |
3 | OBJ_ENCODING_ZIPMAP | 压缩字典 ( redis < 2.6 ) |
4 | OBJ_ENCODING_LINKDELIST | 双端链表 ( redis < 3.2 ) |
5 | OBJ_ENCODING_ZIPLIST | 压缩列表 |
6 | OBJ_ENCODING_INTSET | 整数集合 |
7 | OBJ_ENCODING_SKIPLIST | 跳跃表 |
8 | OBJ_ENCODING_EMBSTR | embstr编码的简单动态字符串 |
9 | OBJ_ENCODING_QUICKLIST | 快速链表 ( redis >= 3.2 ) |
10 | OBJ_ENCODING_STREAM | 流 ( redis >= 5.0.0 ) |
11 | OBJ_ENCODING_LISTPACK | 紧凑列表 ( redis >= 7.0.0 ) |
备注:redis < 3.2 编码方式以“REDIS_”开头,不是“OBJ_”
字符串编码类型
- int
存储 8 个字节的长整型(long,263-1) - embstr
代表 embstr 格式的 SDS,存储小于 44 个字节的字符串。
RedisObject 对象头和 SDS 对象连续存在一起,使用 malloc 方法分配一次内存空间 - raw
存储大于 44 个字节的字符串,需要分配两次内存空间(分别为 Redis Object 和 SDS 分配空间)
备注:3.2 版本之前是 39 个字节
底层数据结构
动态字符串 sds
redis版本 < 3.2
embstr : redisObject(16)+sds{char(39) + int(4*2=8) + 1(结尾的\0)} = 64字节
typedef struct sdshdr{
//记录buf数组中已使用字节的数量
//等于 SDS 保存字符串的长度
unsigned int len;
//记录 buf 数组中未使用字节的数量
unsigned int free;
//字节数组,用于保存字符串
char buf[];
}
redis版本 >= 3.2
-
sdshdr5:25 = 32 byte
-
sdshdr8:28 = 256 byte
-
sdshdr16:216 = 65536 byte = 64KB
-
sdshdr32:232 = 65536 byte = 4GB
-
sdshdr64:264 byte = 224 TB = 16 EB
embstr : redisObject(16)+sds{char(44) + uint8_t(1*2=2) + char(1) + 1(结尾的\0)} = 64字节
/*以sdshdr8为例*/
struct __attribute__ ((__packed__)) sdshdr8 {
//当前字符数组的长度
uint8_t len;
//当前字符数组总共分配的内存大小
uint8_t alloc;
//当前字符数组的属性,用来标识sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64
unsigned char flags;
//字符串真正的值
char buf[];
};
链表 list
typedef struct list{
//表头节点
listNode *head;
//表尾节点
listNode *tail;
//节点值复制函数
void (*dup) (void *ptr);
//节点值释放函数
void (*free) (void *ptr);
//节点值对比函数
int (*match) (void *ptr,void *key);
//链表所包含的节点数量
unsigned long len;
}list;
typedef struct listNode{
//前置节点
struct listNode *prev;
//后置节点
struct listNode *next;
//节点的值
void *value;
}listNode
/*迭代器*/
typedef struct listIter {
listNode *next;
int direction;
} listIter;
字典 hashtable
typedef struct dictht{
//哈希表数组
dictEntry **table;
//哈希表大小
unsigned long size;
//哈希表大小掩码,用于计算索引值
unsigned long sizemask;
//该哈希表已有节点的数量
unsigned long used;
}dictht
typedef struct dictEntry{
void *key;
union{
void *val;
uint64_tu64;
int64_ts64;
}v;
struct dictEntry *next;
}dictEntry
跳跃表 skiplist
typedef struct zskiplistNode {
struct zskiplistLevel{
struct zskiplistNode *forward;
unsigned int span;
}level[];
struct zskiplistNode *backward;
double score;
robj *obj;
} zskiplistNode;
typedef struct zskiplist{
//表头节点和表尾节点
structz skiplistNode *header, *tail;
//表中节点的数量
unsigned long length;
//表中层数最大的节点的层数
int level;
}zskiplist;
整数集合 intset
typedef struct intset{
//编码方式
uint32_t encoding;
//集合包含的元素数量
uint32_t length;
//保存元素的数组
int8_t contents[];
}intset
压缩列表 ziplist
/* Each entry in the ziplist is either a string or an integer. */
typedef struct {
/* When string is used, it is provided with the length (slen). */
unsigned char *sval;
unsigned int slen;
/* When integer is used, 'sval' is NULL, and lval holds the value. */
long long lval;
} ziplistEntry;
紧凑列表 listpack
listpack作为ziplist的替代者,它的内存布局、实现原理和ziplist非常相似。
listpack内存更紧凑,实现更简洁。
/* Each entry in the listpack is either a string or an integer. */
typedef struct {
/* When string is used, it is provided with the length (slen). */
unsigned char *sval;
uint32_t slen;
/* When integer is used, 'sval' is NULL, and lval holds the value. */
long long lval;
} listpackEntry;
数据类型对应的底层数据编码
类型 | 编码方式 | 版本 | 条件 |
---|---|---|---|
OBJ_STRING | OBJ_ENCODING_INT | 8个字节的长整型 | |
OBJ_STRING | OBJ_ENCODING_EMBSTR | 小于等于44字节 | |
OBJ_STRING | OBJ_ENCODING_RAW | 大于44字节 | |
OBJ_LIST | OBJ_ENCODING_ZIPLIST | redis < 3.2 | 元素个数少于512,且value小于等于64字节 |
OBJ_LIST | OBJ_ENCODING_LINKEDLIST | redis < 3.2 | 元素个数大于512,或者value大于64字节 |
OBJ_LIST | OBJ_ENCODING_QUICKLIST | redis >= 3.2 | 全部 |
OBJ_SET | OBJ_ENCODING_INTSET | 集合中的元素都是整数且元素个数小于512(默认值) | |
OBJ_SET | OBJ_ENCODING_HT | 其他 | |
OBJ_ZSET | OBJ_ENCODING_SKIPLIST | 元素个数大于128(默认),或者value大于64字节 | |
OBJ_ZSET | OBJ_ENCODING_ZIPLIST | redis < 7.0 | 元素个数少于128(默认),且value小于等于64字节 |
OBJ_ZSET | OBJ_ENCODING_LISTPACK | redis >= 7.0 | 元素个数少于128(默认),且value小于等于64字节 |
OBJ_HASH | OBJ_ENCODING_HT | filed的个数大于512,或者value大于64字节 | |
OBJ_HASH | OBJ_ENCODING_ZIPLIST | redis < 7.0 | filed的个数少于512,且value小于等于64字节 |
OBJ_HASH | OBJ_ENCODING_LISTPACK | redis >= 7.0 | filed的个数少于512,且value小于等于64字节 |