为了实现从键到值的快速访问,Redis 使用了一个哈希表来保存所有键值对。

一个哈希表,其实是一个数组,数组的每个元素称为一个哈希桶。

哈希桶中的 entry 元素中保存了 *key 和 *value 指针

哈希表存在哈希冲突问题和 rehash 可能带来的操作阻塞

Redis 解决哈希冲突的方式,就是链式哈希。就是指同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接(叫做哈希冲突链)。

Redis 的 rehash

哈希冲突链上的元素只能通过指针逐一查找再操作。如果哈希表里写入的数据越来越多,哈希冲突可能也会越来越多,这就会导致某些哈希冲突链过长,进而导致这个链上的元素查找耗时长,效率降低。对于追求“快”的 Redis 来说,这是不太能接受的。

所以,Redis 会对哈希表做 rehash 操作。rehash 也就是增加现有的哈希桶数量,让逐渐增多的 entry 元素能在更多的桶之间分散保存,减少单个桶中的元素数量,从而减少单个桶中的冲突。

rehash 过程

为了使 rehash 操作更高效,Redis 默认使用了两个全局哈希表:哈希表 1 和哈希表 2。一开始,当你刚插入数据时,默认使用哈希表 1,此时的哈希表 2 并没有被分配空间。随着数据逐步增多,Redis 开始执行 rehash。
这个过程分为三步:

给哈希表 2 分配更大的空间,例如是当前哈希表 1 大小的两倍;
把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;
释放哈希表 1 的空间。

到此,我们就可以从哈希表 1 切换到哈希表 2,用增大的哈希表 2 保存更多数据,而原来的哈希表 1 留作下一次 rehash 扩容备用。

这个过程看似简单,但是第二步涉及大量的数据拷贝,如果一次性把哈希表 1 中的数据都迁移完,会造成 Redis 线程阻塞,无法服务其他请求。此时,Redis 就无法快速访问数据了。

为了避免这个问题,Redis 采用了渐进式 rehash。

渐进式 rehash

简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。如下图所示:

这样就巧妙地把一次性大量拷贝的开销,分摊到了多次处理请求的过程中,避免了耗时操作,保证了数据的快速访问。

在进行渐进式 rehash 的过程中, 会同时使用 哈希表1 和 哈希表2 两个哈希表, 所以在渐进式 rehash 进行期间, 字典的删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行: 比如说, 要在Redis 里面查找一个键的话, 程序会先在 哈希表1 里面进行查找, 如果没找到的话, 就会继续到 哈希表2 里面进行查找, 诸如此类。
另外, 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 哈希表2 里面, 而 哈希表1 则不再进行任何添加操作: 这一措施保证了 哈希表1 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。

渐进式rehash执行时,除了根据键值对的操作来进行数据迁移,Redis本身还会有一个定时任务在执行rehash,如果没有键值对操作时,这个定时任务会周期性地(例如每100ms一次)搬移一些数据到新的哈希表中,这样可以缩短整个rehash的过程。

Redis的渐进式Rehash相关推荐

  1. Redis之渐进式rehash

    渐进式 rehash 上一节说过, 扩展或收缩哈希表需要将 ht[0] 里面的所有键值对 rehash 到 ht[1] 里面, 但是, 这个 rehash 动作并不是一次性.集中式地完成的, 而是分多 ...

  2. 【Redis】什么是渐进式rehash

    字典 字典是一种用于保存键值对的抽象数据结构.比如set msg "hello redis"这个键值对就是保存在数据库字典中 字典还是哈希键的底层实现之一,当一个哈希键包含的键值对 ...

  3. Redis:缩容、扩容、渐进式rehash

    目录 1.缩容 扩容 2.渐进式rehash 1.缩容 扩容 随着redis的操作的不断执行,哈希表保存的键值会逐渐地增多或者减少,为了让哈希表的负载因子(ratio)维持在一个合理的范围之内,当哈希 ...

  4. redis渐进式rehash机制

    在Redis中,键值对(Key-Value Pair)存储方式是由字典(Dict)保存的,而字典底层是通过哈希表来实现的.通过哈希表中的节点保存字典中的键值对.我们知道当HashMap中由于Hash冲 ...

  5. 单线程照样飞起 | redis字典快速映射+hash釜底抽薪+渐进式rehash

    前言 相信你一定使用过新华字典吧!小时候不会读的字都是通过字典去查找的.在Redis中也存在相同功能叫做字典又称为符号表!是一种保存键值对的抽象数据结构 本篇仍然定位在[redis前传]系列中,因为本 ...

  6. Redis详解(六)渐进式rehash机制

    在Redis中,键值对(Key-Value Pair)存储方式是由字典(Dict)保存的,而字典底层是通过哈希表来实现的.通过哈希表中的节点保存字典中的键值对.我们知道当HashMap中由于Hash冲 ...

  7. redis中的hash扩容渐进式rehash过程

    背景: redis字典(hash表)当数据越来越多的时候,就会发生扩容,也就是rehash 对比:java中的hashmap,当数据数量达到阈值的时候(0.75),就会发生rehash,hash表长度 ...

  8. hash地址_redis中的hash扩容、渐进式rehash过程

    背景: redis字典(hash表)当数据越来越多的时候,就会发生扩容,也就是rehash 对比:java中的hashmap,当数据数量达到阈值的时候(0.75),就会发生rehash,hash表长度 ...

  9. 四、redis的底层数据结构

    1.演示数据类型的实现 上篇博客我们在介绍 key 相关命令的时候,介绍了如下命令: OBJECT ENCODING key 该命令是用来显示那五大数据类型的底层数据结构. 比如对于 string 数 ...

最新文章

  1. android用户界面之菜单(Menu)教程实例汇总
  2. 谷歌下一代AI架构、Jeff Dean宣传大半年的Pathways终于有论文了
  3. Android Display buffer_handle_t的定义
  4. php在双引号中输出变量要加大括号,php中输出变量加大括号{}作用_PHP教程
  5. 计算机专业核心技术,计算机系多媒体核心技术实验室建设专业方案(10页)-原创力文档...
  6. nginx工作进程处理请求的系统调用
  7. SLB+Tomcat时request.RemoteAddr无法获取正确的客户端IP的问题解决方案
  8. Linux编译websocketpp解决方案
  9. BIM标准丨深圳市住房和建设局关于印发《房屋建筑工程招标投标建筑信息模型技术应用标准》
  10. 全网首发!如何停止莫名其妙的软件下载?终于被我找到了!
  11. 如何查看计算机开机启动的服务,开机启动项在哪里设置 开机启动项设置方法【图文】...
  12. QT中的LIBS用法
  13. 谷歌浏览器 如何设置在新标签页打开链接
  14. vba 添加outlook 签名_outlook2007使用vba签名的问题
  15. PDF文件太大怎么压缩,一分钟学会压缩PDF
  16. 真香,华为主动离职也给 N+1
  17. Python(十一) 原生爬虫
  18. Arcgis中的标注操作(一)
  19. bash中正确处理文件或路径名中的空格
  20. 通达信自动交易系统接口安装方式

热门文章

  1. 【吐血整理】史上最全的《Java面试题及解析》
  2. java 正则匹配详解
  3. 如何使Android应用程序获得root权限
  4. 发明专利申请需要的材料
  5. hbase怎么修改表名?
  6. 互联网与神经学的交叉对比研究--论文全文
  7. Socket编程实现文件的传输
  8. 剖析强化学习 - 第六部分
  9. ROS联合webots实战案例(四)webots中使用激光雷达
  10. css伪元素before和after用法详解