redis数据结构之字典

字典(dictionary),其实和符号表(symbol table),关联数组(associative array),映射(map)是一个东东,都是为了保存键值对(k-v pair)的数据结构,屌屌哒。

PHP中因为能很方便的用关联数组,因此能写出很多实用高效的代码,有空一定要去好好了解下PHP的关联数组是如何实现的!

redis的字典数据结构由 dict, dictType, dictht, dictEntry构成(当然,像字典这种稍微复杂点的数据结构当然是自己设计了迭代器的。)

上述几种数据结构的关系图如下:


大概就是说字典嘛,以dict结构体为核心,dictType是针对不同数据类型设置的特殊处理函数(包括哈希方法,key复制,value复制,key对比,析构等函数),有了这个,dict可以支持不同类型的K-V pair,非常灵活,支持了多态字典。而dict中的privdata为一些特定函数提供了参数。

字典的更底层数据结构,是由哈希表组成,而哈希表,则是上图中的dictht数据结构,一个字典dict中有个哈希表结构dictht的数组,包含俩哈希结构实例:ht[0]和ht[1]

单个哈希表结构dictht包含一个指向单个哈希结点(dictEntry)的二级指针,可以把它理解成一个二维数组,最终指向的哈希结点结构dictEntry则实际存储着对应的k-v对

那么问题来了,redis的哈希算法是什么?如何解决碰撞的呢?

哈希算法:murmurhash2(教材上说最新的已经是murmurhash3了,这个有待扩展学习)

解决碰撞:链地址法(seperate chaining)操作。


为什么要维护两个哈希结构ht[0]和ht[1]呢?

哈希表有个参数叫负载因子(load factor),定义是 已使用节点数/总的size, 由于采用了链地址发应对碰撞,所以已使用节点是完全可以大于总的size的。

一般情况下, 数据都是针对ht[0]来进行读写。当负载因子不合理时,需要对ht[0]的空间和数据进行重新整理,提高数据读写效率。

所以需要ht[1]作为一种缓冲,根据特定策略重新调整新的大小配置到ht[1],并逐步把ht[0]的数据搬移到ht[1]上,当数据和空间都折腾完毕后,ht[1]就可以当做ht[0]来应付正常的redis数据读写需求了,这时候再创建ht[1]备用,方便下次再调整。这整个过程称作 “重复哈希”(rehash),这样动态地调整哈希表结构,提高了读写效率。

同时由于rehash涉及到数据搬移,所以当ht[0]中保存着大量数据时,redis当然不会无脑地移动大量数据,而是让数据在执行增删查改时,执行完后附带把ht[0]的数据搬迁到ht[1]上,这就把一个大的任务拆散成了很多小的行为,分而治之,提高了效率,这个过程称为渐进式哈希。

好困,明天再补充吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值