Redis专题--字典

《redis设计与实现》--第四章

字典,是一种用于保存键值对的抽象数据结构。字典中的每个键都是独一无二的,redis的数据库就是使用字典来作为底层实现的,字典还是哈希键的底层实现之一。

redis的字典由dict.h/dict结构表示:

参数说明:
type:是一个指向dictType结构的指针,每个dictType结构保存了一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数。
privdata:保存了需要传给那些类型特定函数的可选参数。

ht属性是包含两个元素的数组,数组的每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0],而ht[1]只会在对ht[0]进行rehash时使用。

使用哈希表作为底层实现。由dict.h/dictht结构定义:

table是一个数组,数组中的每个元素都指向dict.h/dictEntry结构的指针,每个dictEntry都保存着一个键值对。

当添加一个新键值对到字典里面时,首先根据键计算出hash值(使用MurmurHash2算法,优点在于即使输入的键是有规律的,算法仍能给出一个很好的随机分布性,且算法的计算速度也非常快),再计算出索引值,最后将包含新键值对的哈希表节点放到哈希表数组的指定索引上,采用头插法(链表没有指向表尾的指针,为了速度考虑,选用头插法,复杂度为O(1))。

如果发生键冲突,使用链地址法来解决,通过nect指针连接起来。

rehash
1. 负载因子:

2. rehash目的与过程:
rehash目的:为了让哈希表的负载因子维持在一个合理的范围之内,当哈希表保存的键值对数量太多或者太少时,程序需要对哈希表的大小进行相应的扩展或者收缩。
rehash过程:

  • (1)为字典的ht[1]哈希表分配空间,这个哈希表的空间大小取决于要执行的操作,以及ht[0]当前包含的键值对数量:如果执行的是扩展操作,那么ht[1]的大小为第一个大于等于ht[0].used * 2的 2^n(2 的 n 次方幂);如果执行的是收缩操作,那么ht[1]的大小为第一个大于等于ht[0].used的 2^n 。
  • (2)将保存在ht[0]中的所有键值对rehash到ht[1]上面:rehash指的是重新计算键的哈希值和索引值,然后将键值对放置到ht[1]哈希表的指定位置上。
  • (3)当ht[0]包含的所有键值对都迁移到了ht[1]之后(ht[0]变为空表),释放ht[0],将ht[1]设置为ht[0],并在ht[1]新创建一个空白哈希表,为下一次rehash做准备。

3. rehash的条件:
扩展操作的条件(满足其中一个):

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

在执行BGSAVE命令或者BGREWRITEAOF命令时,redis需要创建当前服务器进程的子进程,而大多数操作系统都采用写时复制(copy-on-write)技术来优化子进程的使用效率,所以在子进程存在期间,服务器会提高负载因子,这样可以避免在子进程存在期间进行哈希表扩展操作,避免不必要的内存写入操作,最大限度地节约内存。
收缩操作的条件:
当哈希表的负载因子小于0.1时,程序自动开始对哈希表执行收缩操作。

渐进式rehash
  为了避免海量数据rehash对服务器性能造成影响,服务器不是一次性将ht[0]里面的所有键值对全部rehash到ht[1],而是分多次、渐进式地将ht[0]里面的键值对慢慢地rehash到ht[1]。
 渐进式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进行期间,字典会同时使用ht[0]和ht[1]两个哈希表,所以rehash期间字典的删除、查找、更新等操作会在ht[0]和ht[1]两个哈希表上进行。例如,查找一个键,首先会在ht[0]中查找,查不到则到ht[1]中查找。另外,新添加的键值对都只会被保存到ht[1]中。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值