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 许可协议。转载请注明来自 爱吃胡萝卜!

