分布式一致性Hash算法原理及实现

news2024/11/16 21:28:10

文章目录

  • 一致性Hash原理
  • 提高容错性和和扩展性
  • 一致性Hash实现
    • 思路
    • 代码

一致性Hash原理

简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环
如假设某哈希函数 H 的值空间为 0 ~ 2^32-1(即哈希值是一个32位无符号整形)

提高容错性和和扩展性

1,用户访问时,根据用户的 IP 使用上面相同的函数 Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针行走,遇到的第一台服务器就是其应该定位到的服务器。
2,注意这里提高容错性,用到了虚拟节点设置在圆环上,这个虚拟节点本质就是与物理节点进行绑定的一个节点,这里想到的是map形式进行绑定

一致性Hash实现

思路

1.hash值是一个非负整数,把非负整数的值范围做成一个圆环;
2.对集群的节点的某个属性求hash值(如节点名称),根据hash值把节点放到环上;
3.对数据的key求hash值,一样的把数据也放到环上,按顺时针方向,找离他最近的节点,就存储到这个节点上。(这个圆环相当于有序的集合,且为了方便查找,存储结构使用treeMap)

圆环中的存储的数据节点结构如下图所示:
在这里插入图片描述

代码

public class Node {

    private String id;

    private String name;

    private List<String> datas = new ArrayList<>();


    public Node() { }

    public Node(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }


    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setDatas(List<String> datas) {
        this.datas = datas;
    }

    public List<String> getDatas() {
        return datas;
    }

    @Override
    public String toString() {
        return "Node【" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", datas=" + datas.toString() +
                '】';
    }
}
@Data
public class HashUtilServe {

    // 存放物理节点
    private List<Node> nodeList = new ArrayList<>();

    // 设置每个物理节点的虚拟节点50个
    private int virtalNodeNum = 50;

    // 物理节点和虚拟hash节点key进行关联
    private HashMap<Node,List<Integer>> virNode = new HashMap<>();

    // 定义一个hash集合存放节点
    private SortedMap<Integer,Node> sortedMap = new TreeMap<>();

    /**
     * 增加服务节点
     * @param node
     */
    public  void  createServe(Node node){
        // 加入物理节点
        nodeList.add(node);
        ArrayList<Integer> hashlist = new ArrayList<>();
        // 创建虚拟节点
        for(int i=0; i<virtalNodeNum; i++){
            int hashValue = FNVHash1(node.getId() + "-" + i);
            hashlist.add(hashValue);
            sortedMap.put(hashValue,node);
        }virNode.put(node,hashlist);
    }

    /**
     * 删除服务节点(模拟物理节点宕机)
     * @param node
     */
    public void deleteServe(Node node){
        // 删除物理节点
        nodeList.remove(node);
        // 删除对应的物理节点
        List<Integer> hashs = virNode.get(node);
        for (Integer hash : hashs) {
            sortedMap.remove(hash);
        }
        // 删除关联表
        virNode.remove(node);
    }

    /**
     * 查好数据对应服务节点
     * @param data
     * @return
     */
    public Node findServe(String data){

        // 对数据进行hash
        int hashValue = FNVHash1(data);

        // 获取【key>=hashvalue】的虚拟节点的map
        SortedMap<Integer, Node> findedMap = sortedMap.tailMap(hashValue);

        if(findedMap.isEmpty()){
            // 只有一台服务器节点并且当前数据缓存的服务器宕机了,找不到服务节点
            return null;
           //  return sortedMap.get(sortedMap.firstKey());
        }
        // 拿最近一台的服务器节点
        return  findedMap.get(findedMap.firstKey());
    }

    /**
     * 分布式缓存存储数据
     * @param data
     * @return
     */
    public Node saveData(String data){

        // 对数据进行hash
        int hashValue = FNVHash1(data);

        // 获取【key>=hashvalue】的虚拟节点的map
        SortedMap<Integer, Node> findedMap = sortedMap.tailMap(hashValue);

        Node node =new Node();
        if(findedMap.isEmpty()){
            // 只有一台服务器节点
            node = sortedMap.get(sortedMap.firstKey());
        }
        // 拿最近一台的服务器节点
        node = findedMap.get(findedMap.firstKey());

        // 将数据缓存到对应服务节点中
        List<String> datas = node.getDatas();
        datas.add(data);
        node.setDatas(datas);
        return node;
    }

    // 散列工具类
    public int FNVHash1(String data) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < data.length(); i++)
            hash = (hash ^ data.charAt(i)) * p;
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;
        //如果算出来的值为负数,则取其绝对值
        if(hash < 0){
            hash = Math.abs(hash);
        }
        return hash;
    }
}
public class DemoPract {
    public static void main(String[] args) {

        // 创建三台服节点对象
        Node serv1 = new Node("192.168.0.1", "serv1");
        Node serv2 = new Node("192.168.0.5", "serv2");
        Node serv3 = new Node("192.168.0.11", "serv3");

        HashUtilServe hashUtil = new HashUtilServe();
        // 将服务器添加到Hash环上
        hashUtil.createServe(serv1);
        hashUtil.createServe(serv2);
        hashUtil.createServe(serv3);

        // 缓存数据到服务节点上
        hashUtil.saveData("1今天是个好日子");
        hashUtil.saveData("2理想要有的");
        hashUtil.saveData("3很厉害的事情");
        hashUtil.saveData("啊哈java才是最牛的");

        Node serve33 = hashUtil.findServe("3很厉害的事情");
        System.out.println(serve33.toString());

        // 删除服务节点3
        hashUtil.deleteServe(serv3);
        System.out.println("---------删除服务3节点----------------");

        Node serve1 = hashUtil.findServe("1今天是个好日子");
        Node serve2 = hashUtil.findServe("2理想要有的");
        Node serve3 = hashUtil.findServe("3很厉害的事情");
        System.out.println(serve1.toString());
        System.out.println(serve2.toString());
        System.out.println(serve3.toString());

    }
}

测试结果如下:
如图所示:可以看到服务器3宕机之后,再查询原来缓存到到服务3的数据,发现三号服务器的缓存数据查询不到了
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/497841.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搜狗百科怎么创建?搜狗百科创建指南(经验分享)

搜狗百科是一个允许用户创建、编辑和维护百科全书的网站。它是搜狗搜索旗下的一个产品&#xff0c;为用户提供了一个共享知识的平台。创建一个搜狗百科词条并非难事&#xff0c;但需要遵守一些注意事项。 话不多说。小媒同学将介绍搜狗百科词条的创建过程和注意事项。 一、创建…

java基础入门-04-【集合学生管理系统】

Java基础入门-04-【集合&学生管理系统】 11、集合&学生管理系统11.1.ArrayList集合和数组的优势对比&#xff1a;11.1.1 ArrayList类概述11.1.2 ArrayList类常用方法11.1.2.1 构造方法11.1.2.2 成员方法11.1.2.3 示例代码 11.1.3 ArrayList存储字符串并遍历11.1.3.1 案…

【观察】甲骨文以“双引擎”驱动,加速中国企业拥抱决策智能

毫无疑问&#xff0c;当前中国整体经济形态正在从传统经济向数字经济转型&#xff0c;千行百业也在加速数字化转型&#xff0c;特别是随着企业数据的沉淀越来越庞大&#xff0c;对数据平台以及智能决策等新技术的需求也越来越旺盛。 国家发布的《“十四五”数字经济发展规划》中…

视频里的音乐怎么转换成mp3格式?

视频里的音乐怎么转换成mp3格式&#xff1f;视频里的音乐转换为mp3的原因有很多&#xff0c;主要是因为mp3格式是一种音频格式&#xff0c;文件大小较小&#xff0c;更易于存储和传输。相比之下&#xff0c;视频格式则是一种视频文件格式&#xff0c;虽然包含音频&#xff0c;但…

Q-in-Q 和 MAC-in-MAC

例题引入&#xff1a; 1. 城域以太网在各个用户以太网之间建立多点第二层连接&#xff0c;IEEE802.1ad定义运营商网桥协议提供的基本技术是在以太网帧中插入&#xff08;26&#xff09;字段&#xff0c;这种技术被称为&#xff08;27&#xff09;技术。 (26)A.运营商VLAN标记…

Hive知识点的回顾

一、Hive的序列化和反序列化 Hive读取文件机制&#xff1a;读取文件中的每一行 > 反序列化 > 通过分隔符进行切割&#xff0c;返回数据表中的每一行对象。 Hive写文件机制&#xff1a;把数据表中的每一行Row对象 > 调用LazySimpleSerde类中的序列化方法 > 把Row对象…

基于AT89C51单片机的电子秒表设计与仿真

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87759735?spm1001.2014.3001.5503 源码获取 主要内容&#xff1a; 设计一个电子钟,实现对时、分、秒的显示的控制,电路采用24小时计时方式。另一个功能是秒表功能…

JVM内存模型和结构介绍

什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;JVM是一个虚构出来的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等。 为什么需要JVM&#xff1f; Java语言使用Java虚拟机屏蔽了与具体平台相关的信息&…

执行网格中有特定数量节点的传感器网络部署(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 ​无线传感器网络是通过大量分布的传感器节点作为终端来协同感知和自主地监测外部世界,以多跳、自组织或协作的方式进行通信和…

Java 基础进阶篇(十二)—— Arrays 与 Collections 工具类

文章目录 一、Arrays工具类1.1 Arrays 类常用方法1.2 对于 Comparator 比较器的支持1.3 Arrays 的综合应用1.3.1 应用一&#xff1a;数组的降序排序1.3.2 应用二&#xff1a;根据学生年龄进行排序 二、Collections工具类2.1 Collections 类常用方法2.2 Collections 排序相关 AP…

哈希表相关知识总结

一、哈希表的定义 散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。也就是说&#xff0c;它通过计算一个关于键值的函数&#xff0c;将所需查询的数据映射到表中一个位置…

C++相比于C语言增加的8个特性(详解)

C相比于C语言增加的8个特性&#xff08;详解&#xff09; 文章目录 C相比于C语言增加的8个特性&#xff08;详解&#xff09;一、命名空间二、C输入和输出三、缺省参数四、函数重载五、引用六、内联函数七、auto关键字八、指针空值nullptr总结 一、命名空间 c的命名空间是为了…

【刷题之路】LeetCode 21. 合并两个有序链表

【刷题之路】LeetCode 21. 合并两个有序链表 1、题目描述二、解题1、方法1——直接合并1.1、思路分析1.2、代码实现 2、方法2——递归2.1、思路分析2.2、代码实现 1、题目描述 原题连接&#xff1a; 21. 合并两个有序链表 题目描述&#xff1a; 将两个升序链表合并为一个新的 …

Camtasia Studio2023Mac最新电脑版屏幕录像软件

Camtasia Studio2023提供了强大的屏幕录像、视频的剪辑和编辑、视频菜单制作、视频剧场和视频播放功能等。它能在任何颜色模式下轻松地记录屏幕动作&#xff0c;包括影像、音效、鼠标移动的轨迹&#xff0c;解说声音等等&#xff0c;另外&#xff0c;它还具有及时播放和编辑压缩…

数字化转型导师坚鹏:美的集团数字化转型案例研究

美的集团数字化转型案例研究 课程背景&#xff1a; 很多企业存在以下问题&#xff1a; 不清楚企业数字化转型能否成功&#xff1f; 不知道其它企业数字化转型的实际做法&#xff1f; 不知道其它企业的数字化转型战略是如何演变的&#xff1f; 课程特色&#xff1a; 用…

汽车架构-工作流程 以及相关协议解读

全车架构&#xff08;E/E&#xff09; 车载测试阶段&#xff1a; 台架测试 HIL测试&#xff08;硬件在环测试&#xff09; ADAS智能辅助驾驶测试 OTA测试&#xff08;远程升级测试&#xff09; 测试工具&#xff1a; Can协议工具&#xff1a;Canoe Pcan Zcanpro 辅助工具…

【Stable Diffusion】ControlNet基本教程(三)

接上篇【Stable Diffusion】ControlNet基本教程&#xff08;二&#xff09;&#xff0c;本篇再介绍两个ControlNet常见的基本用法&#xff0c;更多用法欢迎关注博主&#xff0c;博主还会更新更多有趣的内容。 3.3更换物体皮肤 有时&#xff0c;我们不想改变物体的轮廓&#xff…

毫米波雷达系列 | 传统CFAR检测(均值类)

毫米波雷达系列 | 传统CFAR检测&#xff08;均值类&#xff09; 文章目录 毫米波雷达系列 | 传统CFAR检测&#xff08;均值类&#xff09;1.CA-CFAR算法2.SO-CFRA算法3.GO-CFAR算法4.仿真对比 CFAR检测器主要用于检测背景杂波环境中的雷达目标&#xff0c;常见的均值类CFAR检测…

数据结构之队列的详解

文章目录 一.什么是队列二.队列的使用2.1 队列的基本操作2.2 队列的基本使用 三.队列的模拟实现3.1 数组实现队列3.2 链表实现队列 四.队列的应用4.1 设计循环队列4.2 设计双端队列4.3 队列实现栈4.4 栈实现队列 五.总结 一.什么是队列 队列是一种先入先出(FIFO)的线性表数据结…

点评项目导入

文章目录 开篇导读项目地址导入SQL项目架构介绍后端项目导入前端项目导入 开篇导读 实战篇我们要学习以下内容 短信登录 这一块我们会使用redis共享session来实现 商户查询缓存 通过本章节&#xff0c;我们会理解缓存击穿&#xff0c;缓存穿透&#xff0c;缓存雪崩等问题&…