“nginx
孤单的人啊孤单的歌c++
孤单的时候别唱情歌面试
写歌的人写着他的寂寞算法
不必定和你适合数据库
悲伤的人啊悲伤的歌缓存
悲伤的剧情不一样角色服务器
编剧的人编着谁的快乐网络
何须演的那么深入负载均衡
都是平凡的人分布式
不是仙也不是神
不悲不喜
该得不可得
爱过的疼过的好聚又好散的
幻想中苦笑不得
不悲不喜该得不可得
见过的路过的获得又失去的
虚幻中成疯成魔
”
在敲代码的时候,来一首寂寞的歌,无限循环中,多了些不同的滋味。
以前,咱们聊过度布式系统设计实践,详细的能够查看一下以前的原创发文。其中,提到了分布式系统设计实践中经常使用的算法,一致性Hash算法。并无细致的对其作讲解,今天碰巧遇到小伙伴问,那么把这个说一下。
一致性哈希算法,是一种分布式哈希(DHT)算法,主要解决了分布式哈希的单调性和分散性问题。
单调性,指的要对已经存在的内容可以正常映射,避免在节点增减过程当中,没法命中,相似于上文说的哈希取模分配,若是几点不断增长,计算方式就会失去平衡。分散性,指的就是解决哈希取模分配的不平衡问题。
一致性哈希的论文发表于1997年,阅读无障碍的同窗能够直接看看大佬的论文理解更深入,附上论文下载连接:http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.147.1879
既然咱们要聊一致性Hash,首先要把Hash这个基础概念理解透彻、弄明白。
哈希(Hash)是最多见的数据分布形式。
常见的哈希算法有MD五、CRC 、MurmurHash 等算法,简单介绍一下。
MD5消息摘要算法(MD5 Message-Digest Algorithm),一种被普遍使用的密码散列函数,能够产生出一个128位(16字节)的散列值(hash value),MD5算法将数据(如一段文字)运算变为另外一固定长度值,是散列算法的基础原理。由美国密码学家 Ronald Linn Rivest设计,于1992年公开并在 RFC 1321 中被加以规范。
循环冗余校验(Cyclic Redundancy Check)是一种根据网络数据包或电脑文件等数据,产生简短固定位数校验码的一种散列函数,由 W. Wesley Peterson 于1961年发表。生成的数字在传输或者存储以前计算出来而且附加到数据后面,而后接收方进行检验肯定数据是否发生变化。因为本函数易于用二进制的电脑硬件使用、容易进行数学分析而且尤为善于检测传输通道干扰引发的错误,所以得到普遍应用。
MurmurHash 是一种非加密型哈希函数,适用于通常的哈希检索操做。由 Austin Appleby 在2008年发明,并出现了多个变种,与其它流行的哈希函数相比,对于规律性较强的键,MurmurHash的随机分布特征表现更良好。
这个算法已经被不少开源项目使用,好比libstdc++ (4.6版)、Perl、nginx (不早于1.0.1版)、Rubinius、 libmemcached、maatkit、Hadoop等。
哈希(Hash)实现方式是经过散列方法,经过计算,就能够映射数据和处理节点关系。
常见的散列方法以下:
场景:
在分布式系统环境下,数据库采用了水平分库,不一样机器上安装了相同的库。那么,该如何选择哪一个机器节点进行增删改查?
很明显,咱们如何选择节点,就是须要选择一个合适的方式进行负载均衡。假使咱们采用普通的hash算法进行负载均衡,并选择简单的「取模法」来讲明这个过程。
假设有 3 个服务器节点编号 [0 - 2],6 次动做编号 [1 - 6],则完成哈希映射以后,三个节点数据映射状况以下:
哈希计算公式:动做% 节点总数 = Hash节点下标
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
经过Hash取模法,每一个动做都均匀的分散到了三个不一样的服务器节点上,看起来很完美!
可是,在分布式集群系统的负载均衡实现上,这种模型有两个问题:
在弹性伸缩的性能要求下,服务节点常常须要扩容缩容。
节点变化使原来计算的哈希值不许确,为了达到负载均衡的效果,要从新计算并更新哈希值,对于更新后哈希值不一致的原动做归属,要迁移到更新后的节点上去。
假设新增了 1 个服务器节点,由原来的 3 个服务节点变成 4 个节点编号 [0 - 3],哈希映射状况以下:
哈希计算公式:动做% 节点总数 = Hash节点下标
1 % 4 = 1
2 % 4 = 2
3 % 4 = 3
4 % 4 = 0
5 % 4 = 1
6 % 4 = 2
能够看到后面三个 :四、五、6 对应的存储节点所有失效了,这就须要把这几个节点的缓存数据迁移到更新后的节点上 (费时费力) ,也就是由原来的节点 [1, 2, 0] 迁移到节点 [0, 1, 2],迁移后存储示意图以下:
线上环境服务节点虽然有各类高可用性保证,但仍是是有宕机的可能,即便没有宕机也有缩容的需求。无论是宕机和缩容均可以归结为服务节点删除的状况,下面分析下服务节点删除对负载均衡哈希值的影响。
同理,面对服务器节点减小,仍要面对Hash从新计算,数据迁移的问题。
普通哈希算法实现的负载均衡各类各样的实际问题,因此咱们引入一致性哈希算法。
一致性哈希,哈希函数计算方法不变,经过构建环状的 Hash 空间替代了原来普通的线性 Hash 空间。
哈希环,是一个足够大的Hash空间(通常是 0 ~ 2^32)
哈希环构建完毕,咱们能够根据上边的场景采用一致性Hash形式,进行优化。
能够用服务器的 IP 或 主机名计算获得哈希值,计算获得的哈希值就是服务节点放置在 Hash 环上。
最后,对每一个操做一样也计算一次哈希值,计算以后的哈希也映射到环上,沿顺时针的方向找到的环上的第一个节点。下图举例展现了节点的选择状况。
相较普通的Hash方式,扩展能力获得了必定提高。那么,一致性哈希是如何解决这个问题的呢?
咱们看一下,以下图所示,当服务器集群要新增一个节点时,会发生什么。受影响的只有动做3,原本3是在ip:0,如今移到ip:3上 便可,其他节点存储的数据保持不动。
普通哈希算法当某一服务节点宕机下线,也会致使原来哈希映射的大面积失效,失效的映射触发数据迁移影响服务性能,容错能力不足。一块儿来看下一致性哈希是如何提高容错能力的。
以下图所示,假设一个节点宕机下线,则只需按顺时针方向选择新的节点存放便可,不会对其余节点数据产生影响。一致性哈希能把节点宕机形成的影响控制在顺时针相邻节点之间,避免对整个集群形成影响。
上边咱们介绍了一致性哈希如何解决普通哈希的扩展和容错问题,原理比较简单,在理想状况下能够良好运行,但在实际使用中还有一些实际问题须要考虑,下面具体分析。
哈希环的空间很大,若是节点比较少,这会致使什么问题呢?
可能的一种状况是,较少的服务节点哈希值汇集在一块儿,好比下图所示这种状况,数据按顺时针寻找节点就致使全都存储到一个节点上去,给单个节点很大的压力!这种状况称为数据倾斜。
一致性哈希-数据倾斜
数据倾斜和节点宕机均可能会致使缓存雪崩。
数据倾斜致使全部数据都打到 单个节点上面,有可能会致使被压垮,节点宕机,数据又都打到 另外一个节点上面,以后又进行传递。这时候故障就像像雪崩时滚雪球同样越滚越大。
还有一种状况是节点因为各类缘由宕机下线。 在数据量特别大的状况下也可能致使节点雪崩。
总之,连锁反应致使的整个缓存集群不可用,就称为节点雪崩。
一致性Hash,经过建立「虚拟节点」的方式解决。
以前咱们说,一致性Hash解决了单调性、分散性。其中关键的一个技术就是虚拟节点。
所谓虚拟节点,就是对原来单一的物理节点在哈希环上虚拟出几个它的分身节点,这些分身节点称为「虚拟节点」。打到分身节点上的数据实际上也是映射到分身对应的物理节点上,这样一个物理节点能够经过虚拟节点的方式均匀分散在哈希环的各个部分,解决了数据倾斜问题。
因为虚拟节点分散在哈希环各个部分,当某个节点宕机下线,他所存储的数据会被均匀分配给其余各个节点,避免对单一节点突发压力致使的节点雪崩问题。
下图展现了虚拟节点的哈希环分布,其中左边是没作虚拟节点状况下的节点分布,右侧是完成虚拟节点配置的节点分布
一致性哈希-虚拟节点
嗖嗖嗖,高大上的算法,实现起来,真的也就那么一回事。特别是在面试中,不少时候,面试官的刁难从一致性Hash开始。那么,相信,今天咱们聊完,已经对一致性hash有深刻理解了,来来来,吊打面试官吧!!
继续听歌!