Redis渐进式哈希

redis渐进式哈希 相信大家对hashMap都不陌生,其底层结构是数组加链表加红黑树(红黑树这里不展开),数组默认大小为16,通过key的hash值可以实现从键到值的快速访问。

redis中字典的实现底层利用了两个数组,使用渐进式rehash来避免数组扩容时rehash带来的性能问题。 1 dict是redis中非常重要的数据结构,也是查询高性能的秘诀之一,很多地方都会用到。 2.dict底层由数组加链表组成,通过对key进行散列求到了hash值对应到数组索引,就可以将该键值的元素存放到该索引下,如果遇到了hash冲突,则通过单向链表的形式将多个元素关联起来。 3.dict底层通过2个数组来实现渐进式rehash,在字典不需要扩容时,默认只会使用到一号数组,待需要扩容时则会初始化二号数组,之后添加的元素都会挂载到二号数组上,并通过字典的其他操作进行单步的rehash,渐渐的将一号数组中的元素迁移至二号数组,待迁移完毕后,二号数组上位成为新的一号数组。

在redis的实现中,没有集中的将原有的key重新rehash到新的槽中,而是分解到各个命令的执行中,以及周期函数中 在redis中每一个增删改查命令中都会判断数据库字典中的哈希表是否正在进行渐进式rehash,如果是则帮助执行一次 类似的在dictFind、dictGenericDelete、dictGetRandomKey、dictGetSomeKeys等函数中都有以下语句判断是否正在进行渐进式rehash

在redis周期函数中,如果发现有字典正在进行渐进式rehash操作,则会花费1毫秒的时间,帮助一起进行渐进式rehash操作 因为在进行渐进式 rehash 的过程中, 字典会同时使用 ht[0] 和 ht[1] 两个哈希表, 所以在渐进式 rehash 进行期间, 字典的删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行: 比如说, 要在字典里面查找一个键的话, 程序会先在 ht[0] 里面进行查找, 如果没找到的话, 就会继续到 ht[1] 里面进行查找, 诸如此类。

另外, 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。