Redis设计与实现 -- 链表与字典
1. 链表
1.1 链表的结构

在 Redis 中,链表的实现是双向链表,除此之外与常规的链表不同的是它还有三个函数指针,dup 函数用于复制链表节点所保存的值,free 函数用于释放链表节点保存的值,match 函数则用于对比链表节点的值和另一个值是否相等。
1.2 总结

2. 字典
2.1 字典的定义
Redis 的字典与 C++ 的 map 类似,key 与 value 进行关联,一个字典可以包含多个键值对。
2.2 哈希表的实现
Redis 的字典底层实现为哈希表,一个哈希表有多个哈希节点,每个哈希节点保存着一个键值对。Redis 的哈希表结构定义如下。

其中 table 为一个 dictEntry 数组,每个元素保存着一个键值对, dictEntry 的结构定义如下。

为了防止哈希后键冲突,dictEntry 设计了一个 next 字段,形成了一个链表,键冲突后的结构如下图所示:

2.3 字典

在 dict 结构体中 ht 字段是一个长度为 2 的数组,每个元素都是一个 dictht 哈希表,默认使用 ht[0],ht[1] 在对 ht[0] 进行 rehash 的时候使用,trehashidx 表示 rehash 的进度,值为 -1 的时候表示目前没有在 rehash。普通状态下的 dict (没有 rehash)如下所示

2.4 哈希算法


2.5 键冲突
当有多个键被分配到哈希数组的同一索引上时,则产生了键冲突,Redis 解决该问题的方法是使用链地址法,即每个节点都有一个 next 指针, 多个哈希表的节点可以使用 next 指针连接起来,由于 dictEntry 节点组成的链表没有指向尾部的指针,如果在尾部插入需要 O(N) 的时间复杂度,考虑到效率问题,总是将新节点插入在链表的头部。

以上图为例,插入一个新的 dictEntry 节点,键值对为 k2, v2,可以看出是插入到头部的。
2.6 rehash
当哈希表的键值对过多或者过少时,会对哈希表的大小进行相应的扩展或者收缩。rehash 的步骤如下:



哈希表的扩展收缩都是自动的,当以下条件满足时自动开始对哈希表进行扩展动作:
- 服务器目前没有执行 BGSAVE 命令或者 BGREWRITEAOF 命令且哈希表的负载因子大于等于 1 。
- 服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令且哈希表的负载因子大于等于 5 。
负载因子的计算公式为:ht[0].used / ht[0].size 。如一个大小为 512,包含 256 个键值对的哈希表来说, 其 负载因子为 256 / 512 = 0.5,当负载因子小于 0.1 时,自动执行收缩操作。
2.7 渐进式 rehash
哈希表的扩展和收缩是将所有的键值对 rehash 到 ht[1] 中,而这个 rehash 的过程不是一次性将所有的键值对 rehash 过去,而是分多次渐进式的进行,原因在于当键值对过多,如数百万个时,计算量过于庞大可能导致服务器在一段时间停止服务。这种渐进式的 rehash 步骤如下:





Redis设计与实现 -- 链表与字典的更多相关文章
- Redis 设计与实现 4:字典
Redis 中,字典是基础结构.Redis 数据库数据.过期时间.哈希类型都是把字典作为底层结构. 字典的结构 哈希表 哈希表的实现代码在:dict.h/dictht ,Redis 的字典用哈希表的方 ...
- 2.redis设计与实现--链表
1.链表节点: 2.链表: 3.总结
- Redis 设计与实现 8:五大数据类型之哈希
哈希对象的编码有两种:ziplist.hashtable. 编码一:ziplist ziplist 已经是我们的老朋友了,它一出现,那肯定就是为了节省内存啦.那么哈希对象是怎么用 ziplist 存储 ...
- Redis 设计与实现 9:五大数据类型之集合
集合对象的编码有两种:intset 和 hashtable 编码一:intset intset 的结构 整数集合 intset 是集合底层的实现之一,从名字就可以看出,这是专门为整数提供的集合类型. ...
- [Redis]Redis的设计与实现-链表/字典/跳跃表
redis的设计与实现:1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要对两个数据表执行join操作 ...
- redis 笔记01 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表
文中内容摘自<redis设计与实现> 简单动态字符串 1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态 ...
- Redis数据结构—链表与字典的结构
目录 Redis数据结构-链表与字典的结构 链表 Redis链表节点的结构 Redis链表的表示 Redis链表用在哪 字典 Redis字典结构总览 Redis字典结构分解 Redis字典的使用 Re ...
- Redis数据结构—链表与字典
目录 Redis数据结构-链表与字典 链表 Redis链表节点的结构 Redis链表的表示 Redis链表用在哪 字典 Redis字典结构总览 Redis字典结构分解 哈希算法 解决键冲突 rehas ...
- Redis设计与实现 (二): 链表
Redis实现为双链表结构, 列表键的底层实现之一就是链表, 发布与订阅, 慢查询, 监视器等功能都用到了链表. Redis本身也使用链表维持多个客户端. 节点定义, 位于 adlist.h/lis ...
随机推荐
- CSP-S2019 停课日记
前言 不想上文化课,于是就停课了 (雾) \(10.13\) 停课前一天 今天名义上是放假,所以不算停课. 老师和同学们听说我要停课,都十分的不舍.我啥也没说就悄悄溜到一中来了. \(10.14\) ...
- alert(1) to win 14
<!--<script></script>之间的内容会被当作js处理,所以,//we'll use this later </script>被注释了.最终 i ...
- voc数据集坐标,coco数据集坐标
voc,如上图 x1 ,y1 ,x4, y4 bbox的坐标格式是,x,y的最大最小值,也就是box的左上角和右下角的坐标 coco x,y,w,h box左上角的坐标以及宽.高 图 ...
- C++数组读入MATLAB数据
data = rand(8, 10); fid = fopen('File.data', 'w'); if fid == - 1 error('Cannot open file for writing ...
- Flask学习笔记03之路由
1. endpoint from flask import Flask, url_for # 实例化一个Flask对象 app = Flask(__name__) # 打印默认配置信息 # 引入开发环 ...
- SpringBoot怎么访问html文件
pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- linux如何查看端口被哪个进程占用的方法
linux如何查看端口被哪个进程占用的方法: 1.lsof -i:端口号2.netstat -tunlp|grep 端口号 都可以查看指定端口被哪个进程占用的情况[步骤一]lsof -ilsof -i ...
- [CSP-S模拟测试]:柱状图(树状数组+二分+三分)
题目描述 $WTH$获得了一个柱状图,这个柱状图一共有$N$个柱子,最开始第$i$根柱子的高度为$x_i$,他现在要将这个柱状图排成一个屋顶的形状,屋顶的定义如下:$1.$屋顶存在一个最高的柱子,假设 ...
- 台哥原创:java 扫雷源码
扫雷,十年前大学时候开发的,界面参照的电脑自带扫雷游戏. 一直是我最喜欢的单机游戏,现在微软的新系统都不能玩了. 幸好还有自己开发的,可以过下瘾.程序员就有这点好处嘛. 这几年陆陆续续,把这个扫雷 ...
- PHP csv导出数据 (二)
全部导出和时间导出 html代码,全程并不需要引用什么插件 <include file="public@header"/> <link href="__ ...