Redis内部存储结构
所属分类 redis
浏览量 1186
8 大类型使用的内部存储结构
string sds
list quicklist
set dict
zset 元素及value小于阈值 ziplist , 否则 zskiplist
hash 元素及value小于阈值 ziplist ,否则 hash
bitmap sds
hyperloglog sds
geo 元素及value小于阈值 ziplist , 否则 zskiplist
redisDb
数据库实例 , 每个 Redis 16 个 redisDb
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
Dict
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
type 保存 hash 函数及 key/value 赋值、比较函数
ht[2] 存储数据的数组 ,默认使用 0 号数组,如果 0 号哈希表元素过多,则分配一个 2 倍 0 号哈希表大小的空间给 1 号哈希表,然后进行逐步迁移
rehashidx 迁移位置标志
Dictht & DictEntry
typedef struct dictht {
# 哈希表数组
dictEntry **table;
# 哈希表大小
unsigned long size;
#哈希表大小掩码
unsigned long sizemask;
# 该哈希表已有节点的数量
unsigned long used;
} dictht;
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
dictEntry
key sds 字符串
value 存储各种数据类型的 redisObject
redisObject
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;
type
数据类型 7 种类型
OBJ_STRING
OBJ_LIST
OBJ_SET
OBJ_ZSET 有序集合
OBJ_HASH
OBJ_MODULE 模块
OBJ_STREAM 消息队列/流
encoding
内部编码方式 10 种编码方式
OBJ_ENCODING_RAW
OBJ_ENCODING_INT
OBJ_ENCODING_HT
OBJ_ENCODING_ZIPLIST
OBJ_ENCODING_ZIPMAP
OBJ_ENCODING_SKIPLIST
OBJ_ENCODING_EMBSTR
OBJ_ENCODING_QUICKLIST
OBJ_ENCODING_STREAM
OBJ_ENCODING_INTSET
LRU
LRU 时间 或 LFU 频率 或时间
refcount
引用计数 , 计数为 0 表明该对象没有被使用,会被释放,回收内存
ptr 指向存储数据的指针
sds simple dynamic string
sdshdr5 sdshdr8 sdshdr16 sdshdr32 sdshdr64
根据实际长度,选择不同的数据结构
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
除了 sdshdr5 之外,其他的几个数据结构都包含 4 个字段:
len 字符串长度
alloc 给字符串分配的内存大小
flags 当前字节数组的属性
buf 字符串值和结束符 \0
sds 三种编码方式 INT RAW EMBSTR
INT ptr 直接指向具体的数据
#define OBJ_ENCODING_EMBSTR_SIZE_LIMIT 44
robj *createStringObject(const char *ptr, size_t len) {
if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT)
return createEmbeddedStringObject(ptr,len);
else
return createRawStringObject(ptr,len);
}
字符串长度小于等于 44 , 使用 embstr 否则 RAW
object encoding xxx
embstr
raw
embstr 专门用于保存短字符串
raw编码 调用两次内存分配函数分别创建 redisObject 和 sdshdr
embstr编码 调用一次内存分配函数分配一块连续的空间,空间中依次包含redisObject和sdshdr
sds 主要作为字符串的内部数据结构,同时也是 hyperloglog、bitmap 类型的内部数据结构
ziplist(压缩列表)
节约内存,减少内存碎片
连续的内存空间
ziplist 包含 5 个部分
zlbytes ziplist占用的总内存
Zltail 尾节点到起始位置的字节数
Zllen 总共包含的节点/内存块数
Entry 各个数据节点
Zlend 魔数 255,用来标记压缩列表的结束
存储节点 zlentry
typedef struct zlentry {
unsigned int prevrawlensize; /* Bytes used to encode the previous entry len*/
unsigned int prevrawlen; /* Previous entry len. */
unsigned int lensize; /* Bytes used to encode this entry type/len.
For example strings have a 1, 2 or 5 bytes
header. Integers always use a single byte.*/
unsigned int len; /* Bytes used to represent the actual entry.
For strings this is just the string length
while for integers it is 1, 2, 3, 4, 8 or
0 (for 4 bit immediate) depending on the
number range. */
unsigned int headersize; /* prevrawlensize + lensize. */
unsigned char encoding; /* Set to ZIP_STR_* or ZIP_INT_* depending on
the entry encoding. However for 4 bits
immediate integers this can assume a range
of values and must be range-checked. */
unsigned char *p; /* Pointer to the very start of the entry, that
is, this points to prev-entry-len field. */
} zlentry;
prevRawLen 前置节点长度
preRawLenSize
len 当前节点的长度
lensize
encoding 当前节点编码类型
entryData 当前节点数据
ziplist 连续紧凑存储,没有冗余空间,插入新的元素需要 realloc 扩展内存,
如果占用空间太大,realloc 重新分配内存和拷贝的开销会很大,
所以 ziplist 不适合存储过多元素,也不适合存储过大的字符串
ziplist 是 hash、sorted set 的内部存储结构之一,
hash 元素不超过 512 个 ,且值不超过 64个字节,使用 ziplist 作为内存存储结构,
由参数 hash-max-ziplist-entries hash-max-ziplist-value 控制
sorted set ,当元素个数不超过 128个并且值不超过 64 字节,使用 ziplist 来存储,
zset-max-ziplist-entries zset-max-ziplist-value
quicklist(快速列表)
quicklist 3.2 之后引入,用来替换 linkedlist
linkedlist 每个节点有前后指针,要占用 16 字节,且每个节点独立分配内存,容易导致内存碎片化
typedef struct quicklist {
quicklistNode *head;
quicklistNode *tail;
unsigned long count; /* total count of all entries in all ziplists */
unsigned long len; /* number of quicklistNodes */
int fill : 16; /* fill factor for individual nodes */
unsigned int compress : 16; /* depth of end nodes not to compress;0=off */
} quicklist;
typedef struct quicklistNode {
struct quicklistNode *prev;
struct quicklistNode *next;
unsigned char *zl;
unsigned int sz; /* ziplist size in bytes */
unsigned int count : 16; /* count of items in ziplist */
unsigned int encoding : 2; /* RAW==1 or LZF==2 */
unsigned int container : 2; /* NONE==1 or ZIPLIST==2 */
unsigned int recompress : 1; /* was this node previous compressed? */
unsigned int attempted_compress : 1; /* node can't compress; too small */
unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;
quicklist 基于 ziplist 的双向链表,数据分段存储到 ziplist,然后将这些 ziplist 用双向指针连接
quicklist 结构体说明
head tail 分别指向第一个和最后一个 ziplist 节点
count 总的元素个数
len ziplist 节点个数
compress LZF算法的压缩深度
quicklistNode
prev/next 双向指针
ziplist 节点 ,单个 ziplist 节点可以存放多个元素
quicklist 是 list 列表的内部数据结构
头尾读写数据很快,时间复杂度 O(1)
支持从中间任意位置插入或读写元素,但速度较慢,时间复杂度 O(n)
zskiplist(跳跃表)
跳跃表是一种有序数据结构
通过在每个节点维持多个指向其他节点的指针,加速访问
大部分场景,跳跃表的效率和平衡树接近,跳跃表支持平均 O(logN) 和最差 O(n) 复杂度的节点查找,
并且跳跃表的实现比平衡树要简单
使用跳跃表两种场景
sorted set ,如果元素数较多或元素长度较大,使用跳跃表作为内部数据结构。
默认元素数超过 128 或者最大元素的长度超过 64,采用 zskiplist 存储
集群结点中用作内部数据结构
zskiplistNode zskiplist
typedef struct zskiplistNode {
sds ele;
double score;
struct zskiplistNode *backward;
struct zskiplistLevel {
struct zskiplistNode *forward;
unsigned long span;
} level[];
} zskiplistNode;
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
typedef struct zset {
dict *dict;
zskiplist *zsl;
} zset;
跳跃表 zskiplist 结构
header 头节点
tail 尾节点
length 长度,不包含表头节点的节点数量
level 除表头节点外的所有节点中,层数最大的那个节点的层数
zskiplistNode
ele 节点元素
score 节点分数
backward 指向当前节点的前一个节点的指针
level forwad 前进指针 span 跨度, forward 指向的节点到当前节点的距离
上一篇
下一篇
jmx_prometheus_javaagent 使用
jmx_exporter JmxCollector 源码要点
jedis 获取 redis info 信息
kafka-topics.sh 无法获取topic列表及topic信息
kafka之broker-list bootstrap-server 和 zookeeper
Kafka 和 RocketMQ 底层存储简单比较