Redis Hash Tables
Based on Redis 7.0.11.
Hash table 定义
1 | typedef struct dictEntry { |
dictEntry.v
:使用 union 以支持更多具体类型,又共享 8 bytes空间。dictEntry.metadata
:供使用方存放一些自定义数据,柔性数组,不使用时不额外占用空间。dictType
:dict 多态能力,其中expandAllowed
将是否扩容的控制权交给了使用方。dict.ht_table
:一般只有ht_table[0]
在使用,ht_table[1]
只在扩容时被启用。dict.ht_used
:对应dict.ht_table
存放的节点数。dict.rehashidx
:渐进式 rehash 使用。dict.pauserehash
:暂停 rehash,一般在开始遍历前设置,整数值表示有多少个暂停请求。dict.ht_size_exp
:dict.ht_table[N]
的大小用2^dict.ht_size_exp[N]
表示。
扩容与收缩
load factor = ht_used[N] / 2^dict.ht_size_exp[N]
。
扩容
扩容条件:load factor >= 1
扩容大小:dict.ht_size_exp[N] = X
, 其中 X 满足: min(2^X) >= 2 * dict.ht_used[N]
。
Note: 在有子进程执行 BGSAVE
或者 BGREWRITEAOF
时,因为父子进程通过 COW 共享内存,为了避免内存写操作带来内存拷贝,扩容条件变为 load factor >= 5
。
收缩
收缩条件:load factor < 0.1
1 | // server.c |
收缩大小:dict.ht_size_exp[N] = X
, 其中 X 满足: min(2^X) > dict.ht_used[N]
。
Note:与扩容类似,只有在没有子进程时,收缩操作才能进行。
不管是扩容还是收缩,dict
都会进入 rehash 状态,rehash 结束后 ht_table[0]
被替换成 ht_table[1]
。
渐进式 rehash
为了降低扩容或收缩对性能带来的影响,ht_table[0]
中节点会分多次 rehash 到 ht_table[1]
中。
在 rehash CURD:
操作 | 步骤 |
---|---|
Add | 直接写入 ht_table[1] 。 |
Find | 依次查找 ht_table[0] 和 ht_table[1] 。 |
Delete | 依次从 ht_table[0] 和 ht_table[1] 中删除。 |
Update | 依次查找 ht_table[0] 和 ht_table[1] ,然后更新 v 。 |
Key takeaways
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 爱吃胡萝卜!