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设计与实现 -- 链表与字典的更多相关文章

  1. Redis 设计与实现 4:字典

    Redis 中,字典是基础结构.Redis 数据库数据.过期时间.哈希类型都是把字典作为底层结构. 字典的结构 哈希表 哈希表的实现代码在:dict.h/dictht ,Redis 的字典用哈希表的方 ...

  2. 2.redis设计与实现--链表

    1.链表节点: 2.链表: 3.总结

  3. Redis 设计与实现 8:五大数据类型之哈希

    哈希对象的编码有两种:ziplist.hashtable. 编码一:ziplist ziplist 已经是我们的老朋友了,它一出现,那肯定就是为了节省内存啦.那么哈希对象是怎么用 ziplist 存储 ...

  4. Redis 设计与实现 9:五大数据类型之集合

    集合对象的编码有两种:intset 和 hashtable 编码一:intset intset 的结构 整数集合 intset 是集合底层的实现之一,从名字就可以看出,这是专门为整数提供的集合类型. ...

  5. [Redis]Redis的设计与实现-链表/字典/跳跃表

    redis的设计与实现:1.假如有一个用户关系模块,要实现一个共同关注功能,计算出两个用户关注了哪些相同的用户,本质上是计算两个用户关注集合的交集,如果使用关系数据库,需要对两个数据表执行join操作 ...

  6. redis 笔记01 简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表

    文中内容摘自<redis设计与实现> 简单动态字符串 1. Redis只会使用C字符串作为字面量,在大多数情况下,Redis使用SDS(Simple Dynamic String,简单动态 ...

  7. Redis数据结构—链表与字典的结构

    目录 Redis数据结构-链表与字典的结构 链表 Redis链表节点的结构 Redis链表的表示 Redis链表用在哪 字典 Redis字典结构总览 Redis字典结构分解 Redis字典的使用 Re ...

  8. Redis数据结构—链表与字典

    目录 Redis数据结构-链表与字典 链表 Redis链表节点的结构 Redis链表的表示 Redis链表用在哪 字典 Redis字典结构总览 Redis字典结构分解 哈希算法 解决键冲突 rehas ...

  9. Redis设计与实现 (二): 链表

    Redis实现为双链表结构, 列表键的底层实现之一就是链表,  发布与订阅, 慢查询, 监视器等功能都用到了链表. Redis本身也使用链表维持多个客户端. 节点定义, 位于 adlist.h/lis ...

随机推荐

  1. SICP 习题解 第二章

    计算机程序的构造和解释习题解答 Structure and Interpretation os Computer Programs Exercises Answer 第二章 构造数据抽象 练习2.17 ...

  2. [Luogu2600]合并神犇(dp,贪心)

    [Luogu2600]合并神犇 题目背景 loidc来到了NOI的赛场上,他在那里看到了好多神犇. 题目描述 神犇们现在正排成一排在刷题.每个神犇都有一个能力值p[i].loidc认为坐在附近的金牌爷 ...

  3. Arrays基本使用

    public static void main(String[] args) { String[] a = { "a", "b", "c" ...

  4. cmd获取管理员权限等

    鼠标点点点的略过 可输入命令 runas /user:Administrator cmd 或 runas /noprofile /user:Administrator cmd Administrato ...

  5. 22.Express框架——2019年12月19日

    2019年12月19日14:16:36 1. express简介 1.1 介绍 Express框架是后台的Node框架,所以和jQuery.zepto.yui.bootstrap都不一个东西. Exp ...

  6. C++ begin()和end()

    begin(a)指向数组a的第一个元素,end(a)指向数组a最后一个元素之后的一个元素 #include <iostream> using namespace std; int main ...

  7. hdu 6134: Battlestation Operational (2017 多校第八场 1002)【莫比乌斯】

    题目链接 比赛时没抓住重点,对那个受限制的“分数求和”太过关心了..其实如果先利用莫比乌斯函数的一个性质把后面那个[gcd(i,j)=1]去掉,那么问题就可以简化很多.公式如下 这和之前做过的一道题很 ...

  8. LeetCode--058--最后一个单词(java)

    给定一个仅包含大小写字母和空格 ' ' 的字符串,返回其最后一个单词的长度. 如果不存在最后一个单词,请返回 0 . 说明:一个单词是指由字母组成,但不包含任何空格的字符串. 示例: 输入: &quo ...

  9. 阿里云E-HPC联合安世亚太、联科集团共建云超算生态

    5月23日,2018云栖大会武汉峰会,阿里云高级技术专家刘峥和张维,对弹性计算最新上线的 serverless (无服务器化)计算技术Bazaar及基于该技术的容器服务产品 Severless Kub ...

  10. [CSP-S模拟测试]:可爱的精灵宝贝(搜索)

    题目描述 $Branimirko$是一个对可爱精灵宝贝十分痴迷的玩家.最近,他闲得没事组织了一场捉精灵的游戏.游戏在一条街道上举行,街道上一侧有一排房子,从左到右房子标号由$1$到$n$.刚开始玩家在 ...