简介
Redis是一个基于Key-Value的内存模型。
Key的数据类型只有string,Value有String、Hash、Set、List、Zset五种类型。
存储模型详解
1、redisServer
RedisServer中对应着redisServer的对象,一个redisServer中可以存在多个数据库实例。
struct redisServer {
// ...
// redisDb数组,一个redisDb代表着一个redis数据库
redisDb *db;
// 一个RedisServer中包含的redis数据库个数,可以自定义,默认是16
int dbnum;
};
2、redisDb
一个redisDb对应着一个redis数据库实例。
typedef struct redisDb {
//词典,内部使用了hash表的结构,用来存放数据
dict *dict;
//词典,用来存放key的过期时间数据
dict *expires;
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*///一些同步的keys
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
//redisDb的编号
int id; /* Database ID */Redis默认有16个数据库
long long avg_ttl; /* Average TTL, just for stats */
} redisDb;
3、dict
dict中存放了一个dictht数组,长度为2。dictht是一个哈希表。ht[0]用来存放当前数据,ht[1]用于扩容和收缩。
typedef struct dict {
// 特定于类型的处理函数
dictType *type;
// 类型处理函数的私有数据
void *privdata;
// 哈希表(2 个),ht[0]用来存放当前数据,ht[1]用于扩容和收缩。
dictht ht[2];
// 记录 rehash 进度的标志,值为 -1 表示 rehash 未进行
int rehashidx;
// 当前正在运作的安全迭代器数量
int iterators;
} dict;
4、dictht
dictht是一个哈希表,对应的节点叫做dictEntry。
typedef struct dictht {
// 哈希表节点
dictEntry **table;
// 哈希表的大小
unsigned long size;
// size-1,将hashcode和sizemask做&,达到快速取模的效果,就得到存储的下标
unsigned long sizemask;
// 存储元素个数
unsigned long used;
} dictht;
5、dictEntry
具体存放数据的实际节点,里面存放了key和val。
typedef struct dictEntry {
// 键
void *key;
// 值
union {
void *val;
uint64_t u64;
int64_t s64;
} v;
// 后继节点,当发生hash冲突的时候,用于拉链
struct dictEntry *next;
} dictEntry;
6、redisObject
typedef struct redisObject {
//数据类型
unsigned type:4;
//数据编码
unsigned encoding:4;
// 对象最后一次被访问的时间
unsigned lru:REDIS_LRU_BITS;
// 引用计数
int refcount;
// 没有直接存放数据,而是数据的指针
void *ptr;
} robj;
总结
1、redisServer: redis服务器,默认包含了16个redis数据库实例。
2、redisDb: redis数据库实例,包含了了两个词典dict,一个是实际数据词典dict、一个是过期时间词典expires。
3、dict: 词典,用来存放数据,是对哈希表dictht的一个包装。因为涉及到扩容和收缩, 包含了一个长度为2的dictht[],ht[0]负责存放数据,ht[1]负责扩容和收缩。
4、dictht: 哈希表,用来存放数据。利用拉链法来解决哈希冲突。对应的底层节点是dictEntry
5、dictEntry: 哈表表节点。包含了一个key和value,还有后继节点,用于拉链。
6、redisObject: 用来存放value,包含了value的数据类型,编码格式、引用数、以及具体数据的存放指针。