您的位置:首页 > 数据库 > Redis

Redis字典的底层实现

2018-03-06 17:07 218 查看
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]中尽行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: