【Redis】Redis底层数据结构原理--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表等
Redis有五种数据类型string
、list
、hash
、set
、zset(字符串、哈希、列表、集合、有序集合)
并且自实现了简单动态字符串
、双端链表
、字典
、压缩列表(ziplist)
、整数集合
、跳跃表(skiplist)
等数据结构。Redis底层使用了多种数据结构来实现各种特性。对于Redis底层实现的了解,可以让我们对Redis工作原理更加清晰。
Redis的五种数据类型
Redis数据结构与内部编码,如下图:
从上图可知Redis每种数据结构可以有多种实现,比如hash可以用hashtable实现也可以用ziplist实现,这样的好处是当有更好的算法实现的时候,像quickList(快速列表)就是比ziplist和linkedList性能更好,那么这时候用更好的算法来替代底层只需要切换具体的实现方式就可以,而不用改动太多的代码,这个有点类似于设计模式里的策略模式,对于用户来说是无感知的。
redis对象(redisObject)
redis源码内部是有一个redisObject对象,redis的键值都是redisObject对象,即在创建时会生成一个用于键名的redisObject对象和一个用于键值的redisObject对象,它是一个c语言结构体。
其结构体如下:
typedef struct redisObject { // 类型 unsigned type:4; // 编码 unsigned encoding:4; // 指向数据的指针 void *ptr; // 记录对象最后一次被程序访问时间,用于计算空转时长(当前时间-lru) unsigned lru:22; /* lru time (relative to server.lruclock) */ // 引用计数,用于内存回收 int refcount; } robj;
redisObject包含信息:
1.数据类型(type)
数据类型包括对外的数据结构类型,包括string,hash,list,set,sorted set。
2.编码方式(encoding)
编码方式包括raw,int,ziplist,linkedlist,hashmap,intset等内部实现的算法。redis在底层设计的时候比较灵活,编码算法都是可以替换的,比如list有ziplist,linkedlist两种实现,在redis3.2版本中又添加了性能更好的quickList数据结构。
3.数据指针(ptr)
4.虚拟内存(vm)
5.其他信息
结构体中定义中的type:4、encoding:4这种定义方式称为位段类型。位段是C语言中允许在一个结构体中以位为单位来指定其成员所占内存长度,能够用较少的位数存储数据,所以使用位段类型的好处就是避免浪费内存。
简单动态字符串(simple dynamic string,SDS)
虽然Redis是用c语言编写的,但是Redis底层很多地方都哟自己的实现。就比如简单动态字符串。Redis中字符串的表示并没有直接使用C字符串来表示,C字符串仅仅作为字符串字面量。它是以Struct的形式构造了一个SDS的抽象类型。当Redis需要一个可以被修改的字符串时,就会使用SDS来表示。在Redis数据库里,包含字符串值的键值对都是由SDS实现的(Redis中所有的键都是由字符串对象实现的即底层是由SDS实现,Redis中所有的值对象中包含的字符串对象底层也是由SDS实现)。
SDS的定义位于sds.h
struct sdshdr { // buf 中已占用空间的长度 int len; // buf 中剩余可用空间的长度 int free; // 数据空间,默认是使用C字符串的空字符结尾的 char buf[]; };