redis的基本数据结构:String(字符串)、List(列表)、 Hash(哈希)、Set(集合)和 Sorted Set(有序集合),底层数据结构一共有 6 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组。其对应关系如下图所示:

redis 技术架构 redis内部结构_redis

我自己觉得掌握下宏观设计就好了,一开始迷失于细节不太好,还在于整体系统学习。

🌲全局key-value字典

☘️我们总是可以通过一个key去关联string,list,set等等,为什么会有这么多丰富的类型呢?从宏观上去把握一下他的底层实现。

☘️如果你看过java的hashmap的实现那一定会对hash桶记忆深刻,或者学过数据结构,拉链法chain也是耳熟能详的,一个哈希表,其实就是一个数组,数组的每个元素称为一个哈希桶。所以,我们常说,一个哈希表是由多个哈希桶组成的,每个哈希桶中保存了键值对数据。其基本的结构如下图所示。

redis 技术架构 redis内部结构_redis 技术架构_02


☘️hash可以在O(1)的时间内计算出hash值并且找到对应的entry位置,entry里面是一个一个key指针和value指针,其实还有其他信息。☘️但凡碰见hash表的,就一定会有一个冲突(碰撞)问题,并且冲突(碰撞)问题是不能避免的,那么redis采用的呢就是向后探测的方法,也就是说,如果两个key通过hash算法散列到数组里面的时候刚好是同一个位置,那么entry2就会通过next指针挂在entry1之后。

redis 技术架构 redis内部结构_hash表_03


☘️那么链式hash的弊端都知道的,就像单链表一样,一个一个往后探测是比较费时间的。redis中也有自己的rehash过程,就是二次散列,redis默认使用两个全局hash表,在源码中是可以看到的。dictht ht[2];初始条件之下是使用hash表1的,随着插入的数据越来越多,在到达一定的条件之下,他会将hash表1中的内容再次映射进hash表2中,将原来的比较臃肿的表再舒展开。很明显rehash的过程就是一次再散列扩容的过程啦。☘️众所周知,redis是单线程的,如果说触发了rehash这个过程,用户总不能一直阻塞等他reash完毕吧,于是redis出现了这样的技术:incremental rehashing,他们都叫渐进式rehash。

☘️简单来描述下:

redis正常处理请求,处理第一次请求,就顺便把hash表1第一个索引位置上的entry进行散列,映射到hash表2中,再处理一个请求,就把hash表1第二个索引位置上的entry进行散列,以此类推。如图所示

redis 技术架构 redis内部结构_数据结构_04


从整体上来看,是一个全量和增量的关系,一个是一次性完全复制,一个是一边接受请求一边处理,有点像后台处理的意思。

🌲ziplist

☘️在介绍经典list的底层数据结构时,我们先了解第一个知识点,压缩列表,很多人应该和我一样第一次见识,ziplist的设计初衷:更节约内存。其设计如下图所示:

redis 技术架构 redis内部结构_redis_05

  • zlbytes:表示ziplist占用的字节总数
  • zltail:表示ziplist表中最后一项(entry)在ziplist中的偏移字节数。
  • zllen:表示ziplist中数据项(entry)的个数。
  • entry: 表示真正存放数据的数据项
  • zlend:表示最后1个字节,是一个结束标记

我们拿一个linklist进行对比:

redis 技术架构 redis内部结构_hash表_06


☘️一个双向linklist每个节点需要存放pre、data、next,并且存储是使用非连续的内存。而ziplist使用的是连续的内存,并且他们entry的存储通过特定的编码进行存储。内存会省去不少,但是和linklist一样ziplist。

☘️说说缺点吧:

  • 头插尾插是很快的,但是呢,如果说是插在某一个位置,那么后面的元素得先挪个位置,再往里插入,并且根据redis的设计,他是有可能出现连锁更新的!这个时候时间复杂度就变成了O(N^2)。
  • 因为可以直接计算出尾部的位置,而不支持随机存取,查找其他元素的时候时间复杂度是O(N),但是如果里面有字符串的话,字符串本身做比较就是O(N),所以合起来是O(N^2)。

quicklist

☘️对于list我们常用LPUSH,RPUSH等,那么它内部结构大概是怎么样的呢?他是如何做到高效的?这个是这节考虑的事情。list的底层数据结构便是quicklist,引用代码中的注释:

A doubly linked list of ziplists

是的,一个由ziplist组成的双向链表,这就是为什么要先了解下ziplist是何物的目的。其设计如下图所示:

redis 技术架构 redis内部结构_数据结构_07


中间的采用了LZF的压缩算法。具体细节就不在这写了,源码什么的有兴趣可以自己看嘛,c我看起来真的很#费劲。