Redis rehash

发布时间 2023-06-12 17:58:57作者: 白露~

 

Redis rehash 是什么?

Redis rehash 是一种渐进式的哈希表扩展或收缩的机制,用于保持哈希表的负载因子在一个合理的范围内,提高哈希表的性能和空间利用率12。

哈希表是 Redis 的基础数据结构,用于存储键值对。哈希表由一个数组和一个链表组成,数组的每个元素是一个指向链表的指针,链表中存放着具有相同索引值的键值对。索引值是通过对键计算哈希值并与数组大小取模得到的34。

当哈希表中存储的键值对数量增加或减少时,哈希表的负载因子(load factor)也会变化。负载因子是哈希表已保存节点数量和哈希表大小的比值15。如果负载因子过高,说明哈希表中的冲突较多,会影响查找、插入和删除操作的效率;如果负载因子过低,说明哈希表中的空间浪费较多,会占用过多的内存资源。

为了解决这个问题,Redis 设计了 rehash 机制,当以下条件中的任意一个被满足时,程序会自动开始对哈希表执行扩展操作:

  • 服务器目前没有在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 1 ;
  • 服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 5 ;

另一方面,当哈希表的负载因子小于 0.1 时,程序自动开始对哈希表执行收缩操作15。

Redis rehash 的过程是怎样的?

Redis rehash 的过程是渐进式的,也就是说,并不是一次性地将所有键值对从旧的哈希表迁移到新的哈希表,而是分多次进行,在每次执行某个哈希表操作时,顺便将一部分键值对进行 rehash ,直到完成整个 rehash 过程。

具体来说,Redis 的字典(dict)结构中有两个哈希表(ht[0] 和 ht1),还有一个 rehashidx 用来控制 rehash 进度。平时只使用 ht[0] 存储数据,当需要进行 rehash 时,会为 ht1 分配空间,并根据扩展或收缩操作确定新的数组大小。然后将 rehashidx 设置为 0 ,表示开始 rehash 。每次执行某个哈希表操作时(如添加、删除、查找等),都会顺便将 ht[0] 中索引为 rehashidx 的链表上的所有键值对迁移到 ht1 中,并将 rehashidx 加一。这样,在多次执行哈希表操作后,最终会将 ht[0] 中的所有键值对都迁移到 ht1 中。此时,释放 ht[0] ,将 ht1 设置为 ht[0] ,并为 ht1 分配一个空白哈希表,为下一次 rehash 做准备。同时,将 rehashidx 设置为 -1 ,表示 rehash 结束12。

Redis rehash 的优点和缺点是什么?

Redis rehash 的优点是:

  • 可以避免一次性的大规模内存分配和数据迁移,减少内存碎片和性能抖动;
  • 可以根据负载因子的变化动态地调整哈希表的大小,保持哈希表的高效和节省;
  • 可以在 rehash 过程中同时处理对哈希表的读写操作,不影响正常的服务功能;

Redis rehash 的缺点是:

  • 需要额外的空间和时间来维护两个哈希表和 rehashidx ,增加了复杂度和开销;
  • 在 rehash 过程中,对哈希表的操作需要同时考虑两个哈希表,增加了逻辑判断和计算量;
  • 在 rehash 过程中,如果发生故障或重启,可能会导致数据丢失或不一致;