Redis数据结构-字典(dict)
字典的结构
我们来看一下Redis的源码:
dict:字典的结构
1 |
|
先来看一下dictType,看看有哪些方法可以根据不同场景来进行自定义:
1 |
|
再来看下比较重要的一个结构dictht(hash表):
1 |
|
整体结构如下图:
图来源:《Redis设计与实现》
字典数据的存储
首先根据dict的dictType来确定计算hash值的函数,根据这个函数来计算key的hash值
然后根据hash&ht[0].sizemask来计算处于hash节点数组的哪个位置,如果当前位置有值则插入到表头位置,形成一个链表
字典的扩容与缩容
扩容和缩容标准:
扩容:
- 服务器目前没有在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 1 ;
- 服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 5 ;
缩容:
- 当负载因子小于0.1时
负载因子计算公式:
load_factor = ht[0].used/ht[0].size
这里的used的数量等于加入元素的数量,而不是hash表节点数组用了几个
如何扩缩容:
前面我们说过字典(dict)是有两个hash表(dictht)的,当需要扩缩容时,先计算出新的ht[1]的大小,然后把ht[0]的数据都挪到ht[1]里面去,在挪的过程中不是一口气全挪过去,因为数量可能会很大,而是渐进式的去挪,每次有操作才去挪一些。
看一下上述操作的一些细节:
细节一:新的ht[1]的大小时如何计算的?
当扩容时,新的大小为第一个大于等于ht[0].used * 2的2^n(2的n次方幂),例:used = 4 那么第一个大于4*2的2的n次方幂为8(2^3)
当缩容时,新的大小为第一个大于等于ht[0].used 的2^n(2的n次方幂),例:used = 4 那么第一个大于4的2的n次方幂为4(2^2)
细节二:如何渐进式的扩缩容?
这时rehashidx就起作用了,他记录着当前要处理的index,每次进行添加,删除,或者更新操作的时候,就把ht[0]hash表在redhashidx索引上的所有键值对rehash到ht[1]中,然后rehashidx加一,依次进行,因为redis时单线程,所以不用考虑多线程问题。
在扩缩容过程中,当需要查找,删除,更新操作时,需要两个hash表去操作,先在ht[0]找,然后再在ht[1]找,找到就操作,想添加操作,会直接添加到ht[1]中。
Redis的字典(dict)结构大致就这么些内容,这是最基础的数据类型,之所以基础是因为整个数据库都是基于这个数据结构的,其他redis对象也会用字典作为value值的结构,比如hash对象,set对象,zset对象也有用到,这些我们在后面的文章中都会根据具体的命令进行分析。
参考:《Redis设计与实现》黄健宏 著