• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Redis字典实现、Hash键冲突及渐进式rehash详解

    本笔记参考《Redis设计与实现》 P24~ 37

    Redis字典实现

    哈希表节点结构

    typedef struct dictEntry
    {
    	// 键
    	void *key;
    
    	// 值 : 可以是一个指针,或者是一个uint64/int64 的整数
    	union {
    		void *val;
    		uint64_t u64;
    		int64_t s64
    	} v;
    
    	// 指向下一个哈希表节点,形成链表 : 该指针可以将多个哈希值相同的键值对连接在一起,以此解决键冲突的问题。
    	struct dictEntry *next;
    } dictEntry;

    哈希表结构

    typedef struct dictht
    {
    	// 哈希表数据
    	dictEntry **table;
    
    	// 哈希表集合大小
    	unsigned long size;
    
    	// 哈希表大小掩码,用于计算索引值
    	// 总是等于 size - 1
    	unsigned long sizemask;
    
    	// 哈希表已有节点数量
    	unsigned long used;
    } dictht;

    字典

    typedef struct dict 
    {
    	// 类型特定函数
    	dicType *type;
    
    	// 私有数据
    	void *privdata;
    
    	// 哈希表
    	dictht ht[2];
    
    	// rehash 索引
    	// 当rehash不在进行时, 值为-1
    	int rehashidx;
    } dict;

    type属性和privdata属性针对不同类型的键值对,为多态字典而设置。
    ht是包含两个项的数组,每个元素都是一个dictht哈希表,一般情况下字典之是哟个ht[0],ht[1]会在对ht[0]进行rehash的时候使用。
    rehashidx记录了rehash目前的进度,如果目前没有在进行rehash,值为-1。

    哈希算法

    hash = dict->type->hashFunction(key);

    index = hash dict->ht[x].sizemask;

    redis使用的是MurmurHash算法,优点是:输入的键是有规律的时候,算法仍然能给出很好的随机分布性,计算速度也快。

    解决hash冲突

    当有两个或以上的key分配到了hash table数组的同一个index上,称为发生了collision。
    Redis采用链地址法解决冲突,每个hash table节点都有一个next指针,多个hash table节点可以用next指针构成一个单向链表。为了速度考虑,程序总是会将新节点插入到链表头位置。

    rehash

    随着操作不断执行,哈希表保存的key value对会逐渐增加和减少。哈希表有一个统计参数load factor,即负载因子,公式如下:

    # 负载因子 = 哈希表已经保存的节点数量 / 哈希表大小
    load_factor = ht[0].used / ht[0].size;

    为了维持负载因子在一个合理的范围,程序会对哈希表的大小进行相应的扩展或收缩,条件如下:

    1、服务器目前没有执行BGSAVE命令或者BGREWRITEAOF命令,并且哈希表的负载因子 >= 1

    2、服务器正在执行BGSAVE命令或者BGREWRITEAOF命令,且负载因子 >= 5

    渐进式hash

    rehash的动作并不是一次性集中完成的,而是分多次渐进完成。
    如果哈希表中村的键值对数量很多,一次性将键值对全部rehash到ht[1]的计算量十分庞大,可能会导致服务器在一段时间内停止服务。
    渐进式rehash采取分而治之的方法,将rehash键值对所需要的计算工作分摊到每次对字典的CRUD操作上,从而避免了集中式rehash带来的庞大计算量。
    详细步骤如下:
    1、为ht[1]分配空间,让字典同时持有ht[0]和ht[1]两个哈希表
    2、在字典中维护一个索引计数器:rehashidx,将值设置为0,表示rehash工作正式开始。
    3、在rehash进行期间,每次对字典的CRUD操作,程序除了执行指定操作以外,顺带将ht[0]哈希表在rehashidx索引上的所有键值对rehash到ht[1]上,当rehash操作完成后,程序将rehashidx值++
    4、重复迭代操作执行后,ht[0]的数据全部rehash到ht[1]上,将rehashidx设为-1,表明rehash操作已经完成

    需要注意的地方
    在rehash的过程中,对于字典的删除、查找、更新操作会在两个哈希表上执行。如想要查找一个键,现在ht[0]中找,没有找到再去ht[1]
    对于insert操作来说,新添加到字典的键值对会一律保存到ht[1]中,不然还得多一次搬运。

    到此这篇关于Redis字典实现、Hash键冲突以及渐进式rehash的文章就介绍到这了,更多相关Redis 渐进式rehash内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
    • redis中hash表内容删除的方法代码
    • Python操作redis实例小结【String、Hash、List、Set等】
    • Redis String 类型和 Hash 类型学习笔记与总结
    • Redis教程(四):Hashes数据类型
    • SpringBoot+Redis实现数据字典的方法
    • python redis存入字典序列化存储教程
    • redis中Hash字典操作的方法
    上一篇:详解Redis缓存穿透/击穿/雪崩原理及其解决方案
    下一篇:redis如何设置database个数
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Redis字典实现、Hash键冲突及渐进式rehash详解 Redis,字典,实现,Hash,键,冲突,