一致性哈希算法

目的:为了解决分布式系统中缓存key的雪崩问题。

一致性哈希算法在 1997 年由麻省理工学院提出,是一种特殊的哈希算法,在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系;

一致性哈希解决了简单哈希算法在分布式哈希表(Distributed Hash Table,DHT)中存在的动态伸缩等问题;

一致性hash是对固定值2^32取模;

一致性Hash的工作原理或算法

① hash环

② 服务器映射到hash环

使用hash(服务器ip)% 2^32

③ 对象key映射到服务器

Key的Hash值:hash(key)% 2^32

此处的Hash函数可以和之前计算服务器映射至Hash环的函数不同

从缓存对象key的位置开始,沿顺时针方向遇到的第一个服务器,便是当前对象将要缓存到的服务器;

**①②③便是一致性Hash的工作原理:**将原本单个点的Hash映射,转变为了在一个环上的某个片段上的映射!

服务器扩缩容场景

① 服务器减少

把缩减服务器上的所有key顺时针移到下一个服务器即可

② 服务器增加

对相邻的两个服务器上的key进行重分配

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

原因:在Hash环上分配的点太少。导致把环分配的不均衡。

点多,则相应会把环分配的比较均衡。则引入虚拟节点的计算

虚拟节点的计算

  • hash(10.24.23.227#1)% 2^32
  • hash(10.24.23.227#2)% 2^32
  • hash(10.24.23.227#3)% 2^32

三、一致性Hash算法java实现

一致性Hash算法实现

下面我们根据上面的讲述,实现一个一致性Hash算法,这个算法具有一些下面的功能特性:

  • 一致性Hash核心算法;
  • 支持自定义Hash算法;
  • 支持自定义虚拟节点个数;
java 复制代码
package com.job.hash;
 
 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/**
 * 一致性hash算法
 */
public class HashUtil {
 
 
    private static Map<Integer,String>  nodeMap = new HashMap<Integer, String>();
 
    //1024个虚拟节点
    private static int V_NODES = 1024;
 
    private static TreeMap<Integer,String> vNodeMap = new TreeMap<Integer, String>();
    private static final int REAL_NODE_COUNT = 8;
    static {
        nodeMap.put(0,"node_0");
        nodeMap.put(1,"node_1");
        nodeMap.put(2,"node_2");
        nodeMap.put(3,"node_3");
        nodeMap.put(4,"node_4");
        nodeMap.put(5,"node_5");
        nodeMap.put(6,"node_6");
        nodeMap.put(7,"node_7");
 
        /**
         * 虚拟节点和真实节点的映射
         */
        for(int i=0;i<V_NODES;i++){
            vNodeMap.put(i,nodeMap.get(i % REAL_NODE_COUNT));
        }
    }
 
    /**
     * 获取真实节点
     * @param value
     * @return
     */
    public static String getRealServerNode(String value){
        Integer code = (value.hashCode()& 0x7FFFFFFF) % 1024;
        return vNodeMap.ceilingEntry(code).getValue();
    }
 
 
    /**
     * 删除一个节点
     * @param nodeName
     */
    public static void dropNode(String nodeName){
 
        int node = -1;
 
        for(Map.Entry<Integer,String> entry : nodeMap.entrySet()){
            if(entry.getValue().equalsIgnoreCase(nodeName)){
                node = entry.getKey();
                break;
            }
        }
        if(node == -1){
            System.out.println("未找到节点:"+nodeName);
            return;
        }
 
 
        Iterator<Map.Entry<Integer,String>> iter = vNodeMap.entrySet().iterator();
        while (iter.hasNext()){
           Map.Entry<Integer,String> entry =  iter.next();
           Integer key = entry.getKey();
 
           if(key % REAL_NODE_COUNT == node){
               System.out.println("删除节点:"+key+",value:"+entry.getValue());
               iter.remove();;
           }
        }
 
    }
 
    public static void main(String[] args) {
        String requestValue = "hello jason";
        System.out.println("映射关系"+vNodeMap);
        System.out.println(getRealServerNode(requestValue));
        System.out.println("删除节点");
        dropNode("node_3");
        System.out.println("映射关系"+vNodeMap);
        System.out.println(getRealServerNode(requestValue));
    }
 
}
相关推荐
2301_8227032021 分钟前
鸿蒙flutter三方库实战——教育与学习平台:Flutter Markdown
学习·算法·flutter·华为·harmonyos·鸿蒙
Jia ming32 分钟前
C语言实现日期天数计算
c语言·开发语言·算法
无限进步_1 小时前
【C++&string】大数相乘算法详解:从字符串加法到乘法实现
java·开发语言·c++·git·算法·github·visual studio
苏纪云1 小时前
蓝桥杯考前突击
c++·算法·蓝桥杯
W23035765731 小时前
经典算法详解:最长公共子序列 (LCS) —— 从暴力递归到动态规划完整实现
算法·动态规划·最长子序列
pzx_0012 小时前
【优化器】 随机梯度下降 SGD 详解
人工智能·python·算法
小肝一下2 小时前
每日两道力扣,day8
c++·算法·leetcode·哈希算法·hot100
无限进步_2 小时前
【C++】验证回文字符串:高效算法详解与优化
java·开发语言·c++·git·算法·github·visual studio
Meme Buoy2 小时前
18.补充数学1:生成树-最短路径-最大流量-线性规划
数据结构·算法
paeamecium2 小时前
【PAT甲级真题】- Count PAT‘s (25)
c++·算法·动态规划·pat考试·pat