你不知道的Redis数据结构
你不知道的Redis数据结构
Redis数据结构
Redis作为缓存利器,不论是在工作中还是面试中都是需要对其足够了解,那么请你说出Redis的数据结构,你是否了解呢?相信一定有人脱口而出,String、List、Hash、Set、Sorted Set,这里一定一定要注意,问题指的是数据结构而不是数据类型,数据结构是数据类型的底层实现,应该为简单动态字符串、双向链表、压缩列表、哈希表、跳表、整型数组,数据类型和数据结构的关系如下。
了解完这些,我们就知道了Redis键值中的值保存形式,那么Redis的整体结构应该是什么样子呢
Redis的整体结构
Redis为实现快速存储,采用哈希表保存所有的键值对,哈希表本质就是数组,数组的每一个元素称为哈希桶,哈希桶中可以包含多个键值对,所以哈希表由多个哈希桶构成,这里需要注意的是键值对中的value在哈希桶中保存的只是指针,并不是字符串对象或者集合对象,整体结构如下所示
Redis的底层结构决定了所有的键查找时间复杂度都是O(1),因为Redis只需要计算键的哈希值就能得到键对应的数组下标从而得到哈希桶entry对象,从而访问value值,但是也就是因为这一特点衍生了另外一个问题。
哈希冲突
哈希冲突,全局哈希表长度有限那么不同键的哈希值完全有可能相同,也就是说不同键定位到的数组下标可能是同一个,这时就需要借鉴entry对象的next指针(这个可以参考JDK1.7HashMap的底层实现),采用哈希冲突链解决哈希冲突。
哈希冲突解决完毕是不是高枕无忧了呢?必然不是,采用哈希冲突链是能解决哈希冲突的问题,同时也带来了另外一个性能问题,哈希冲突链的访问只能是一个一个往下查找,如果冲突链过长查找效率自然变差,那么只要想办法将冲突链变短是不是就可以解决这个问题,所以Redis提出了Rehash的操作,就是增大哈希桶的数据,让集中存放在哈希桶中的entry对象,分散保存,减少每一个哈希桶的entry对象数(将哈希冲突链变短)从而减少哈希冲突。
Redis的Rehash操作
Redis默认使用两个全局哈希表,哈希表1和哈希表2,其中默认存储的是哈希表1,当哈希表1达到执行Rehash操作时,Redis会执行三个操作:
-
将哈希表2的容量初始化为哈希表1的两倍。
-
将哈希表1的值慢慢转移到哈希表2中。
-
释放哈希表1的空间。
至此Redis就完成了一次rehash,新的数据保存操作会在哈希表2中进行,后面如再需要Rehash时会利用哈希表1进行扩容,完成上述的三个步骤。如果有了解JVM的同学肯定马上想到这种替换操作和幸存0区和幸存1区的作用及其类似。
这里需要注意一个问题,Rehash的步骤2将哈希表1的值转移到哈希表2并不是一次性完成,而是多次执行,称为渐进式rehash,因为哈希表数据量大可能导致Redis线程阻塞,影响业务正常请求。
如图有如下初始数据,假设存在查询请求。
当请求1查询key1的值时其键值下标对应的是哈希表数组下标为1的位置,那么会先遍历数组下标为1的哈希冲突链,得到value值并返回,后面会将哈希冲突链的值从哈希表1转移到哈希表2上(会重新计算哈希)。
当请求2查询key2的值时其键值下标为2同样会执行返回value值的操作同时拷贝值到哈希表2上。
这样的机制就能将一次性大批量的拷贝操作,分摊到多次请求中来完成,避免耗时访问,提升访问效率。
注意点
在进行渐进式rehash时,其实对于哈希表的修改、删除、查询等操作都会在哈希表1和哈希表2中进行,例如查询操作在哈希表1中没有查询到数据就会去哈希表2中查询,其余类似,另外在渐进式哈希执行期间新增操作应该是保存到扩容的哈希表中(上图就是哈希表2,但不是一直都是哈希表2可能多次哈希),这样就能保证被扩容的哈希表(上图指哈希表1)只减不增,随着rehash的进行最后被扩容的哈希表变为空。
哈希表会在每一次请求的时候会将被扩容的哈希表1中数据拷贝到扩容哈希表2中,但如果一个数组下标的值从未有过请求去访问,那么是不是这个哈希表就永远无法完成复制呢?其实并不然就算没有请求去访问一个数组下标,同样会有定时任务去做数组拷贝,这样保证了访问量少的数据同样能复制到新的哈希表中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)