Redis数据结构之字典-dict

dictRedis服务器中出现最为频繁的复合型数据结构,除hash使用dict之外,整个Redis数据库中所有的keyvalue也会组成一个全局字典,还有带过期时间的key集合也是一个字典。

zset集合中存储valuescore的映射关系也是通过dict结构实现的。

结构

// 哈希表
typedef struct dictht {
    dictEntry **table;  // 哈希表数组,二维
    long size;          // 哈希表大小
    long used;          // 哈希表已有节点数
} dictht;
​
// 哈希表节点
typedef struct dictEntry {
    void *key;       //
    void *val;       //
    dictEntry *next; // 指向下一个哈希表节点,形成链表
} dictEntry;

内部是二维数组

dict内部是一个二维数组,包含两个hashtable

通常情况下只有一个hashtable是有值的,但是在扩容、缩容时,需要分配新的hashtable,然后进行渐进式rehash,此时两个hashtable分别是旧的hashtable和新的hashtable。在rehash结束后,旧的hashtable被删除,新的hashtable取而代之。

使用链表法解决哈希冲突

从哈希表节点结构dictEntry中可以看到,每一个节点都有一个指向下一个dictEntry的指针,说明Redis中主要通过使用链表法解决哈希冲突,即每一个hashtable中存储的是一个链表,表中存储指向链表头部元素的指针。

rehash过程

1.为字典分配空间

假设字典中两个hashtable分别为h[0]h[1],数据存储在h[0]中。

在执行rehash之前,需要为h[1]分配空间,这个hashtable的大小取决于需要执行的操作和当前h[0]包含键值对数量即h[0].used

  • 扩展操作:h[1]大小为第一个大于等于h[0].used*22n次方幂

  • 收缩操作:h[1]大小为第一个大于等于h[0].used2n次方幂

2.执行rehash

将保存在h[0]中的键值对rehashh[1]上,rehash指重新计算键的hash值和索引值,然后将键值对放置在h[1]的指定索引位置上

3.释放空间

所有键值对迁移完成之后,h[0]变成空表,此时释放h[0],然后将h[1]设置为h[0],最后在h[1]位置上新创建一个hashtable,为下一次rehash做准备

渐进式rehash

在进行rehash时,需要申请新数组,然后迁移所有键值对,这是一个时间复杂度为O(n)的操作,所以对于大字典的扩容需要耗费一定时间。

为避免阻塞,Redis使用渐进式rehash,多次、渐进地完成迁移,以避免集中式rehash带来的庞大计算量。

扩展、收缩时机

负载因子 = 已保存节点 / 哈希表大小即load_factor = ht[0].used / h[0].size

扩展时机

  • 没有执行BGSAVE/BGREWRITEAOF时,负载因子大于等于1

  • 执行BGSAVE/BGREWRITEAOF时,负载因子大于等于5

收缩时机

  • 负载因子小于0.1

转载于:https://www.cnblogs.com/jeemzz/p/11440923.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值