深入redis hash (字典)内部
数据结构
字典是redis中出现最为频繁的一种数据结构,除了hash类型外,redis中所有的key-value 组成一个全局字典,带有过期时间的key和其过期时间也是一个字典。zset集合中存储的value和score也是一个字典。
struct RedisDB{
dict *dict;//all keys =>value
dict *expires: //all expired key=> time
}
struct zset{
dict *dict;//all value=>score
zskiplist *zsl;
}
redis中的字典结构实际上是有两个hashtable(h(0),h(1)),一般情况下只有一个hashtable是有值的。hashtable的数据结构和java的hashmap是一样的,通过分桶的方式解决hash冲突。当rehash时,会将值迁移到另外一个备用的hashtable中。
java中的rehash是一步到位的,是O(n)级别的操作,redis是单线程的,不允许这样耗时的任务进行,而是通过渐进式rehash的方式进行。
渐进式rehash
1 为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。
2 在字典中维持一个索引计数器变量 rehashidx , 并将它的值设置为 0 , 表示 rehash 工作正式开始。
3 在 rehash 进行期间, 每次对字典执行添加、删除、查找或者更新操作时, 程序除了执行指定的操作以外, 还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值增一。
4 随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。
注意:rehash 阶段 操作都是在两个hashtable上进行的,但是添加操作只会在h(1) 上






扩容、缩容条件
当元素个数等于数组的长度是即开始扩容,扩容大小是增加一倍的容量。如果此时正在bigsave,为了减少内存页的过多分离COW,redis会选择不扩容。但是,当元素个数增加到数组的5倍时,就会强行扩容。
当元素个数小于数组长度的10%,就会触发缩容,缩容是不会考虑bigsave。
本文详细探讨了Redis中的字典数据结构,包括hashtable实现、rehash过程及其条件,以及扩容和缩容策略。重点介绍了如何理解并操作Redis的内置字典,以及为何采用渐进式rehash技术以保持高效性能。
1万+

被折叠的 条评论
为什么被折叠?



