Redis的数据结构
1、Redis是使用C语言开发的一种以键值对形式存储数据的非关系型数据库。
2、Redis的键只能是字符串类型,值可以包括:String、List、Set、Sorted set、Hash等。
3、String类型底层实现
(1)采用简单动态字符串(simple dynamic string,SDS)的抽象类型。
(2)结构定义:
struct sdshdr { // 已使用字节 int len; // 未使用字节 int free; // 字节数组,用于保存字符串 char buf[]; }
(3)不采用C语言字符串,采用SDS的原因有:
获取字符串长度的复杂度为O(1);
API是安全的,不会造成缓冲区溢出;
修改字符串长度N次最多需要执行N次内存重新分配;
可以保存文本或者二进制数据;
兼容部分C字符串函数。
4、List类型底层实现
(1)两种情形:当列表数量比较多,或者元素为较长的字符串时使用双向链表实现;当列表元素较少,或者元素为较短的字符串时使用压缩列表实现。
(2)双向链表底层实现为list(头结点、尾节点、链表长度等)+ listNode(前置指针、后置指针、节点值)结构表示,链表可以用于保存不同类型的值。
(3)压缩列表是一种为节约内存而使用的顺序型数据结构,包含多个节点,每个节点可以保存一个字节数组或者是整数。
5、Set类型底层实现
(1)采用整数集合(intset)来保存整数值的集合抽象数据结构,集合中不会出现重复元素。
(2)结构定义:
typedef struct intset { // 编码方式 unit32_t encoding; // 集合包含的元素数量 unit32_t length; // 保存元素的数组 int8_t contents[]; } intset;
(3)intset底层实现为数组,只支持升级(位数)操作,不支持降级操作。
6、Sorted Set类型底层实现
(1)采用跳跃表来实现,是一种有序数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。
(2)跳跃表底层实现由zskiplist(包括头结点、尾节点、长度)和zskiplistNode(节点,包括层、前进指针、后退指针、跨度、分值、成员对象等)两个结构组成。
(3)每个跳跃表节点的层高都是1至32之间的随机数。
(4)在同一个跳跃表中,多个节点可以包含相同的分值,但每个节点的成员对象必须是唯一的。
(5)跳跃表的节点按照分值大小进行排序,当分值相同时,节点按照成员对象的大小进行排序。
7、Hash类型底层实现
(1)采用字典来实现,字典可以用来实现Redis的数据库和哈希键。
(2)字典底层实现为哈希表,每个字典有两个哈希表,一个平时使用,另一个在rehash时使用。
(3)Redis使用MurmurHash2算法来计算键的哈希值。
(4)哈希表使用链地址法来解决键冲突。
(5)在对哈希表进行扩展或收缩时,需要进行渐进式地rehash操作。
8、Redis对象的含义
(1)Redis数据库中每个键值对的键和值都是一个对象。
(2)Redis的字符串、列表、哈希、集合以及有序集合的对象至少都有两种或以上的编码方式,不同场景下的编码可以优化对象的使用效率。
(3)服务器在执行某些命令之前,会先检查给定键的类型能否执行指定的命令,而检查一个键的类型就是检查键的值对象的类型。
(4)Redis的对象系统带有引用计数实现的内存回收机制,当一个对象不再被使用时,该对象所占用的内存就会被自动释放。
(5)Redis会共享值为0到9999的字符串对象。
(6)对象会记录字节的最后一次被访问时间,这个时间可以用于计算对象的空转时间。