【分布式存储】聊聊一致性哈希算法原理和实现
负载均衡问题
在实际的生产环境中,一般都是提供多个服务进行处理,比如对于用户中心提供多个节点,那么上游系统如何保证获取其中一个节点进行进行处理呢,这就是负载均衡问题。而在服务治理中,dubbo有几种策略。主流的就是加权轮训方式。
但是有一种场景 那就是如果每个节点都保存有状态的数据,我们只想某个用户固定访问固定的机器。你怎么解决, 其实使用hash算法就可以解决, 比如通过用户uid%节点个数 每次访问可以到固定节点节点。虽然这样可以解决,但是在针对节点数量变化的时候,mode就需要变化,这样通常可能导致整体节点重新计算。 所以就引入一致性哈希算法。
原理
他其实就是划分成2^32次方的空间,通过部署不同的节点,然后按照客户端计算的hash,统一的往顺时针找到最近的一个节点进行请求处理。
这样可以避免的问题是什么:就是当一个节点C出现故障 或者 人工下线时,影响的面只有一部分。
但是在极端情况下 可能出现数据节点倾斜的问题。如何解决呢?
其实就是虚拟一致性哈希算法。
通过增加多个虚拟节点,可以均匀的多个承担处理请求。即使某个节点出现故障,影响的范围也小。
code
/**** @author qxlx* @date 2025/7/27 09:43*/
public class ConsistentHash {// 虚拟1024个节点private static final int VIRTUAL_NODE_NUM = 1024;private static final int REAL_NODE_NUM = 10;private Map<Integer,String> realServiceNodes;private Map<Integer,String> virtualServiceNodes;public ConsistentHash() {init();}private void init() {realServiceNodes = new ConcurrentHashMap<>(REAL_NODE_NUM);virtualServiceNodes = new ConcurrentHashMap<>(VIRTUAL_NODE_NUM);// 初始化真实节点for (int i = 0; i < REAL_NODE_NUM; i++) {realServiceNodes.put(i,"192.168.0."+i);}// 初始化虚拟节点for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {virtualServiceNodes.put(i,realServiceNodes.get(i % REAL_NODE_NUM));}}// 根据虚拟节点 查找真实节点public String getRealNodeServer(String key) {// 计算在虚拟节点的位置int index = key.hashCode() % VIRTUAL_NODE_NUM;// 根据虚拟节点 找到真实节点String node = virtualServiceNodes.get(index);if (node == null) {throw new IllegalArgumentException("没有找到对应的服务节点");}return node;}// 删除一个真实节点public void removeRealNode(String realNode) {if (realNode == null) {return;}for (Map.Entry<Integer,String> entry : realServiceNodes.entrySet()) {if (entry.getValue().equals(realNode)) {realServiceNodes.remove(entry.getKey());}}for (Map.Entry<Integer,String> entry : virtualServiceNodes.entrySet()) {if (entry.getValue().equals(realNode)) {virtualServiceNodes.remove(entry.getKey());}}}public static void main(String[] args) {ConsistentHash consistentHash = new ConsistentHash();String realNodeServer = consistentHash.getRealNodeServer("1");System.out.println("realNodeServer:"+realNodeServer);consistentHash.removeRealNode("192.168.0.1");}
}
参考
https://www.cnblogs.com/binyue/p/17344216.html