一文详尽解析Redis的设计原理

本文将redis的设计原理从基础到设计器全部都有讲解,内容较多,建议先收藏再找个合适的时候阅读
 
1.简介Redis中的每个Key-Value在内存中都会被划分成DictEntry、RedisObject以及具体对象,其中DictEntry又分别包含指向Key和Value的指针(以RedisObject的形式)以及指向下一个DictEntry的指针 。

一文详尽解析Redis的设计原理

文章插图
 
Key固定是字符串,因此使用字符串对象来进行表示,Value可以是字符串、列表、哈希、集合、有序集合对象中的任意一种 。
Redis提供了五种对象,每种对象都需要使用RedisObject进行表示 。
Redis使用redisObject结构来表示对象(存储对象的相关信息)
typedef struct redisObject { unsigned type; unsigned encoding; unsigned lru; int refcount; void *ptr;}robj;
type属性:存储对象的类型(String、List、Hash、Set、ZSet中的一种)
encoding属性:存储对象使用的编码方式,不同的编码方式使用不同的数据结构进行存储 。
lru属性:存储对象最后一次被访问的时间 。
refcount属性:存储对象被引用的次数 。
*ptr指针:指向对象的地址 。
使用type命令可以查看对象的类型 。
使用object encoding命令可以查看对象使用的编码方式 。
使用object idletime命令可以查看对象的空转时间(即多久没有被访问,并不会刷新当前RedisObject的lru属性)
使用object refcount命令可以查看对象被引用的次数 。
这些命令都是通过Key找到对应的Value再从Value对应的RedisObject中进行获取 。
2.字符串Redis没有直接使用C语言的字符串,而是自定义了一种字符串类型,以对象的形式存在(C语言的字符串只是单纯的字面量,不能够进行修改)
Redis使用sdshdr结构来表示字符串对象(SDS)
struct sdshdr { int len; int free; char buf[];};
len属性:字符串的长度 。
free属性:未使用的字节数量 。
buf数组:字符串的底层实现用于存储字符 。

一文详尽解析Redis的设计原理

文章插图
 
buf数组中会有空字符,该空字符不会记录在len属性中 。
SDS相比C语言的字符串
C语言中存储字符串的字节数组其长度总是N+1(最后一个是结束符),因此一旦对字符串进行追加则需要重新分配内存 。
为了避免C字符串的这种缺陷,SDS通过未使用的空间解除了字符串长度和底层数组长度之间的关系,在SDS中buf数组的长度不一定就是字符串长度+1,数组里面还可以包含未使用的字节 。
通过未使用的空间,SDS实现了空间预分配和惰性空间释放两种策略,从而减少由于字符串的修改导致内存重分配的次数 。
空间预分配:用于优化SDS保存的字符串的增长操作,当需要对SDS保存的字符串进行增长操作时,程序除了会为SDS分配所必须的空间以外,还会为SDS分配额外的未使用空间 。
惰性空间释放:用于优化SDS保存的字符串的缩短操作,当需要对SDS保存的字符串进行缩短操作时,程序并不会立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些多出来的字节的数量记录出来,等待将来使用 。
3.字典Redis的字典使用散列表作为底层实现,同时字典也是Redis数据库和HashTable编码方式的底层实现 。
一文详尽解析Redis的设计原理

文章插图
 
Redis使用dictht结构来表示散列表
typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used;}dictht;
table属性:散列表 。
size属性:散列表的大小 。
sizemask属性:用于计算索引值 。
used属性:散列表中节点的数量 。
Redis的散列表使用链地址法的方式解决散列冲突,最终就是指针数组的形式,数组中的每个元素都是一个指向DictEntry的指针 。
Redis使用dictEntry结构来表示散列表中的节点
typedef struct dictEntry { void *key; union{ void *val; uint_tu64; int64_ts64; }v struct dictEntry next*;}dictEntry;
key属性:指向Key的指针(即RedisObject)
value属性:可以是一个指向Value的指针(即RedisObject)、uint64_t整数、int64_t整数
next属性:指向下一个DictEntry的指针 。
Redis使用dict结构来表示字典,每个字典包含两个dictht 。
typedef struct dict{ dictType *type; void *privatedata; dictht ht[2]; int rehashidx;}dict;
type属性:指向DictType的指针,每个DictType结构保存了一系列函数 。


推荐阅读