目录

hash一致性

普通hash

假如现在需要向4个redis存取图片,以图片的名字为key,value为图片实际存放的路径,我们可以取到key的hash值,然后就hash值进行模运算,然后就定位到该条数据应该存储到哪个redis节点上了。

通过上面的方法提高了效率,我们在取数据的时候就不用遍历4个redis节点,直接到正确的节点去取数据即可,但是有个缺点:当增加或删除节点时,大量的数据就失效,因为再进行取余运算结果已不同。

一致性hash

其实一致性hash还是进行取模运算,只不过取模不在除以节点数,而是2^32。

有个虚拟的圆环,上面均匀分布0-2^32 -1,就像表盘一样,对key取余后就定位到该数据在圆盘的位置了。

我们同样对redis实例节点进行hash取余,也得到了节点的位置。

对数据顺时针查找最近的redis节点,该节点就是应该存取的节点。

./pic1.jpg

根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

添加或删除节点

现假设Node C不幸宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性Hash算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响

新增节点X时,此时对象Object A、B、D不受影响,只有对象C需要重定位到新的Node X !一般的,在一致性Hash算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它数据也不会受到影响。

综上所述,一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

Hash环的数据倾斜问题

一致性Hash算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,例如系统中只有两台服务器,其环分布如下:

./pic2.jpg

此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。

为了解决这种数据倾斜问题,一致性Hash算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点。具体做法可以在服务器IP或主机名的后面增加编号来实现。

例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点:

./pic3.jpg

例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

总结

hash一致性当节点增加或减少的时候并不能完全做到无感,但是只有少量的数据进行迁移,这样比原来的hash好多了。