首页 > 编程语言 >一致性Hash算法

一致性Hash算法

时间:2022-11-21 11:11:10浏览次数:54  
标签:缓存 Hash 算法 哈希 一致性 服务器 hash

一致性Hash算法

为什么会出现一致性hash

一致性哈希是分布式系统组件负载均衡的首选算法,比如分库分表时要考虑数据怎么均匀分布,它既可以在客户端实现,也可以在中间件上实现。其应用有:
  1. 分布式散列表(DHT)的设计;
  2. 分布式关系数据库(MySQL):分库分表时,计算数据与节点的映射关系;
  3. 分布式缓存:Memcached 的客户端实现了一致性哈希,还可以使用中间件 twemproxy 管理 redis/memcache 集群;
  4. RPC 框架 Dubbo:用来选择服务提供者;
  5. 亚马逊的云存储系统 Dynamo;
  6. 分布式 Web 缓存;
  7. Bittorrent DHT;
  8. LVS。

传统hash算法的弊端

资源数据分布通常有哈希分区和顺序分区两种方式
  1. 顺序分布:数据分散度易倾斜、键值业务相关、可顺序访问、不支持批量操作。
  2. 哈希分布:数据分散度高、键值分布业务无关、无法顺序访问、支持批量操作。
  1. 优点
这种方式的突出优点就是简单,且常用于数据库的分库分表。如京东某系统中采用shardingjdbc,用这种方式进行分库分表路由处理。
  1. 缺点
当节点数量发生变化时,如扩容或收缩节点(没有遇到过),数据节点关系需要重新计算,会导致数据的重新迁移。所以扩容通常采用翻倍扩容,避免数据映射全部打乱而全部迁移,翻倍迁移只发生50%的数据迁移。如果不翻倍缩扩容,如某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将宕掉的服务器使用算法去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;如果新增一台机器,会有N /(N+1)的服务器的缓存数据需要进行重新计算。对于系统而言,这通常是不可接受的颠簸(因为这意味着大量缓存的失效或者数据需要转移)。 传统求余做负载均衡算法,缓存节点数由3个变成4个(3/(3+1)=75%),缓存不命中率为75%。计算方法:穷举hash值为1-12的12个数字分别对3和4取模,然后比较发现只有前3个缓存节点对应结果和之前相同,所以有75%的节点缓存会失效,可能会引起缓存雪崩。 大量缓存在同一时间失效,造成缓存的雪崩,进而导致整个缓存系统的不可用,这基本上是不能接受的; 为了解决优化上述情况,一致性hash算法应运而生~

一致性Hash算法详述

 算法原理

一致性哈希算法在 1997 年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系; 一致性哈希解决了简单哈希算法在分布式哈希表(Distributed Hash Table,DHT)中存在的动态伸缩等问题; 一致性hash算法本质上也是一种取模算法; 不过,不同于上边按服务器数量取模,一致性hash是对固定值2^32取模; IPv4的地址是4组8位2进制数组成,所以用2^32可以保证每个IP地址会有唯一的映射;

① hash环

我们可以将这2^32个值抽象成一个圆环⭕️,圆环的正上方的点代表0,顺时针排列,以此类推:1、2、3…直到2^32-1,而这个由2的32次方个点组成的圆环统称为hash环;

② 服务器映射到hash环

在对服务器进行映射时,使用hash(服务器ip)% 2^32,即: 使用服务器IP地址进行hash计算,用哈希后的结果对2^32取模,结果一定是一个0到2^32-1之间的整数; 而这个整数映射在hash环上的位置代表了一个服务器,依次将node0、node1、node2三个缓存服务器映射到hash环上;

③ 对象key映射到服务器

在对对应的Key映射到具体的服务器时,需要首先计算Key的Hash值:hash(key)% 2^32; :此处的Hash函数可以和之前计算服务器映射至Hash环的函数不同,只要保证取值范围和Hash环的范围相同即可(即:2^32); 将Key映射至服务器遵循下面的逻辑: 从缓存对象key的位置开始,沿顺时针方向遇到的第一个服务器,便是当前对象将要缓存到的服务器; 假设我们有 "semlinker"、"kakuqo"、"lolo"、"fer" 四个对象,分别简写为 o1、o2、o3 和 o4; 首先,使用哈希函数计算这个对象的 hash 值,值的范围是 [0, 2^32-1]: 图中对象的映射关系如下: hash(o1) = k1; hash(o2) = k2; hash(o3) = k3; hash(o4) = k4; 同时 3 台缓存服务器,分别为 CS1、CS2 和 CS3: 则可知,各对象和服务器的映射关系如下: K1 => CS1 K4 => CS3 K2 => CS2 K3 => CS1 即: 以上便是一致性Hash的工作原理; 可以看到,一致性Hash就是:将原本单个点的Hash映射,转变为了在一个环上的某个片段上的映射!   在前面我们已经说过:如果使用简单的取模方法,当新添加服务器时可能会导致大部分缓存失效,而使用一致性哈希算法后,这种情况得到了较大的改善,因为只有少部分对象需要重新分配!

数据偏斜&服务器性能平衡问题

  引出问题   在上面给出的例子中,各个服务器几乎是平均被均摊到Hash环上; 但是在实际场景中很难选取到一个Hash函数这么完美的将各个服务器散列到Hash环上; 此时,在服务器节点数量太少的情况下,很容易因为节点分布不均匀而造成数据倾斜问题;   同时,还有另一个问题: 在上面新增服务器 CS4 时,CS4 只分担了 CS1 服务器的负载,服务器 CS2 和 CS3 并没有因为 CS4 服务器的加入而减少负载压力;如果 CS4 服务器的性能与原有服务器的性能一致甚至可能更高,那么这种结果并不是我们所期望的;  

虚拟节点

针对上面的问题,我们可以通过:引入虚拟节点来解决负载不均衡的问题:   即将每台物理服务器虚拟为一组虚拟服务器,将虚拟服务器放置到哈希环上,如果要确定对象的服务器,需先确定对象的虚拟服务器,再由虚拟服务器确定物理服务器;  

原理总结:

 

原理理解了,实现并不难,主要是一些细节:

    1. hash算法的选择。
      Java代码不要使用hashcode函数,这个函数结果不够散列,而且会有负值需要处理。
      这种计算Hash值的算法有很多,比如CRC32HASH、FNV132HASH、KETAMAHASH等,其中KETAMAHASH是默认的MemCache推荐的一致性Hash算法,用别的Hash算法也可以,比如FNV132_HASH算法的计算效率就会高一些。
    2. 数据结构的选择。根据算法原理,我们的算法有几个要求:
      要能根据hash值排序存储
      排序存储要被快速查找 (List不行)
      排序查找还要能方便变更 (Array不行)
      另外,由于二叉树可能极度不平衡。所以采用红黑树是最稳妥的实现方法。Java中直接使用TreeMap(自动排序的)即可。

使用案例

例如:Jedis下的ShardedJedis (分布式)分片机制 采用了一致性哈希的算法,至少160个虚拟节点,来决定每个key的保存位置,不同的key返回的redis连接可能是不同的。

 

 默认权重是1,虚拟节点是权重*160,即一个物理节点至少160个虚拟节点。虚拟节点hash计算:物理节点(名字或索引序号) 加 数字编号

 

 

 

 

 hash算法(MurmurHash算法) 和 数据结构(划分虚拟节点采用 TreeMap):

 

 



标签:缓存,Hash,算法,哈希,一致性,服务器,hash
From: https://www.cnblogs.com/erlongxizhu-03/p/16910734.html

相关文章

  • 二分查找算法
    是一种针对有序集合的查找算法在python中,有一个模块与之密切相关,就是bisect1importbisect234deffunc():5a=[1,5,9]6bisect.insort(a,6......
  • 每日算法之调整数组顺序使奇数位于偶数前面(二)
    JZ81调整数组顺序使奇数位于偶数前面(二)描述输入一个长度为n整数数组,数组里面可能含有相同的元素,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前面......
  • [排序算法] 桶排序 (C++)
    桶排序解释桶排序思想桶排序是一种空间换取时间的排序方式,是非基于比较的。桶排序顾名思义,就是构建多个映射数据的桶,将数据放入桶内,对每个桶内元素进行单独排序。假设......
  • [排序算法] 计数排序 (C++)
    计数排序解释计数排序思想计数排序的思想十分简单,就是统计每个数字出现的次数。它是一种非基于比较的排序算法,其是通过额外的空间换取时间的方式,来实现更加高效的排序。......
  • 八皇后问题算法
    八皇后问题算法问题引入:在八行八列的格子上放8个皇后(棋子),使得任意两个皇后都攻击不到对方,即使得他们都不在同一行同一列和同一斜线上。思路分析:第一个皇后放在第一......
  • go模拟实现反向代理各种算法
    packageutiltypeHttpServerstruct{HoststringWeightint}typeLoadBalancestruct{Server[]*HttpServerCurrentIndexint}varMapWeight......
  • 实验四:神经网络算法实验
    【实验目的】理解神经网络原理,掌握神经网络前向推理和后向传播方法;掌握神经网络模型的编程实现方法。【实验内容】1.1981年生物学家格若根(W.Grogan)和维什(W.Wirth)发现了......
  • hashcat
    hashcat参考资料https://blog.bbskali.cn/1635.htmlhashcat-m1000-a0-owinpass1.txt--removewin2.hashptemp.txt参数说明:“-m1000”表示破解密码类型为“......
  • Golang实现hashmap
    golang实现hashmap思路:数组+链表->HashMap1.先看一下go里的map是怎么实现的go实现map采用拉链法的实现,如下图所示,键值对中的键会经过一个哈希函数,哈希函数会帮我们找到......
  • [排序算法] 快速排序 (C++) (含三种写法)
    快速排序解释快速排序QuickSort与归并排序一样,也是典型的分治法的应用。(如果有对归并排序还不了解的童鞋,可以看看这里哟~归并排序)❤❤❤快速排序的分治模式1、......