Redis字典的底层实现

redis的字典数据结构设计是最让我觉得精巧的,因为研究过HashMap的源码,一开始并没有觉得到底有什么优秀的地方,也无非就是,数组+链表的形式,但是不同的是在dict这个数据结构中有两张Hash表,一张用来存储,另一张用来做rehash。
先简单说说Hash表的实现方式,就是数组+链表,当要插入或者删除的时候先用一种高级的hash算法求出key的hash值(用的是MurmurHash2算法),然后用 hash值&dict->ht[x].sizemask得到索引下标 (sizemask掩码的大小是数组大小减一,数组大小始终是2的n次方,这些都与HashMap的实现相同),如果插入的时候发生了键冲突的话,就会采用链地址法,用头插法将其插入链表的头部(这样效率比较高)
因为redis讲求高效的存储和插入性能,所以redis对于rehash采用了及其精巧的rehash操作,我这是rehash最让人惊喜的一个地方。
一般来说会在负载因子大于等于五的时候尽行rehash(负载因子=哈希表已经保存的节点数/数组的长度)
渐进式rehash:在redis的字典中,rehash操作不是一步完成的而是渐进式的完成的,因为redis是一个讲求高效率存储和查找的nosql型数据库,而如果Hash表中的元素太多,那么rehash就要进行大量的计算,这样会导致效率降低,所以redis的字典采用了渐进式的rehash操作:
1. 先为ht[1](用来做rehash的表)分配空间,大小>=大于等于原来的hash表数组大小*2的2的整数次方。
2. 在字典中维护一个rehashidx变量,没有rehash的时候这个变量的值是-1,开始rehash的时候它就改成0,
3. 每当对原来的hash表(也就是ht[0]),进行增删改查操作的时候,都会讲hash表中数组下标为rehashidx的那一串链表进行rehash到ht[1]中,当前的rehash完成后rehashidx会增加一。
4. 随着字典操作的不断进行最终会rehash完成所有的ht[0],然后将rehashidx重新弄写成-1,并将ht[0]释放空间,将ht[0]=ht[1],ht[1]=null;
渐进式rehash执行期间的哈希表操作,查找、删除、修改会在两个表中进行(因为两个表都有数据嘛),但是增加操作只在ht[0]中尽行。

你可能感兴趣的:(redis)