浅析一致性哈希算法的原理及实现
Posted 噫!微斯人,吾谁与归
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅析一致性哈希算法的原理及实现相关的知识,希望对你有一定的参考价值。
1.分布式缓存问题
以上是单节点环境下,但随着流量的增大,可能就演变为了如下情形:
❓这个负载均衡算法该如何设计最为合理呢?
首先能想到的最简单的方法可能就是随机或者轮询,这样会产生两个问题:一是数据冗余;二是数据可能已经被缓存,但请求却命中了不存在该数据的节点上。
如何解决这个问题?只需要保证相同的key被发送给相同节点上即可。再一想这不就是hash算法嘛【index = hash(key) % n】(n为节点的数量)
public class SimpleHash
public int loadBalance(String key)
return hash(key) % 3;
private int hash(String key)
int hash = Math.abs(key.hashCode());
.....
.....
return hash;
这种算法它的容错性和扩展性不是很好;一旦某个节点宕机或者加入新的节点时,导致n发生了变化,需要重新hash计算,这样可能导致大量缓存不命中,一瞬间给磁盘数据库造成了很大的压力。
容错性是指当某个节点宕机时,整个系统是否可以继续高效运行;扩展性是指加入新节点时,整个系统是否可以高效运行。
所以这种简单的哈希算法并不适用于实际场景,而本文所讲的一致性哈希算法解决了大量哈希重定位的问题。
2.一致性哈希算法
一致性哈希引入了一个虚拟的圆环,这个圆环有2^32个节点组成(0~ 2^32);
📚它的原理如下:
(1)对每个缓存服务器的IP作为key进行哈希计算,得到的结果一定分布在环上。
(2)对每个数据作为key进行哈希计算,得到的结果也一定分布在环上
按照顺时针,第一台遇到的节点就是该数据定位到的服务器。
❓当节点宕机或者添加新的节点时,它会出现什么样的结果呢?
public class ConsistentHash
private static final String[] NODES = "123.23.34.1", "123.52.2.1", "43.122.54.1";
//模拟环形哈希表
private static final SortedMap<Integer, String> CIRCLE_Map = new TreeMap<>();
static
for (String node : NODES)
int index = hash(node);
System.out.println(node + "节点的哈希值为:" + index);
CIRCLE_Map.put(index, node);
public static String loadBalance(String key)
int index2 = hash(key);
//返回一个大于或等于index2的map
SortedMap<Integer, String> tailMap = CIRCLE_Map.tailMap(index2);
//如果tailMap为空,则直接返回哈希表的第一个数据
if (tailMap.isEmpty())
return CIRCLE_Map.get(CIRCLE_Map.firstKey());
else
//第一个Key就是顺时针过去离node最近的那个结点
return CIRCLE_Map.get(tailMap.firstKey());
private static int hash(String key)
........
........
public static void main(String[] args)
System.out.println("zsh被路由到的节点为:" + loadBalance("zsh"));
此时可以看到只有一小部分数据进行了重定位,所以它具有很好的容错性和扩展性,❓那么它就没一点问题吗?答案肯定不是的,在某种情况下,会出现节点倾斜的问题。
当节点2宕机之后,数据1和数据2都重定位到了节点3上,节点分布式不均匀会导致数据倾斜的问题。
3.引入虚拟节点
解决数据倾斜问题,可以通过增加大量节点使其分布均匀;但是实际上不可行,太浪费钱。所以引入虚拟节点,并将虚拟机节点定位到某个物理节点上即可。
如下图引入v1~v6虚拟节点,并建立与物理节点的映射关系;如定位到v1和v2的数据均定位到节点1上。
带虚拟节点的哈希算法实现
public cl
以上是关于浅析一致性哈希算法的原理及实现的主要内容,如果未能解决你的问题,请参考以下文章