zoukankan      html  css  js  c++  java
  • 分布式hash相关内容

    Hash算法相关内容

    ⾸先有⼀条直线,直线开头和结尾分别定为为1和2的32次⽅减1,这相当于⼀个地址,对于这样⼀条
    线,弯过来构成⼀个圆环形成闭环,这样的⼀个圆环称为hash环。我们把服务器的ip或者主机名求
    hash值然后对应到hash环上,那么针对客户端⽤户,也根据它的ip进⾏hash求值,对应到环上某个位
    置,然后如何确定⼀个客户端路由到哪个服务器处理呢?按照顺时针⽅向找最近的服务器节点
    假如将服务器3下线,服务器3下线后,原来路由到3的客户端重新路由到服务器4,对于其他客户端没有
    影响只是这⼀⼩部分受影响(请求的迁移达到了最⼩,这样的算法对分布式集群来说⾮常合适的,避免
    了⼤量请求迁移 )
    增加服务器5之后,原来路由到3的部分客户端路由到新增服务器5上,对于其他客户端没有影响只是这
    ⼀⼩部分受影响(请求的迁移达到了最⼩,这样的算法对分布式集群来说⾮常合适的,避免了⼤量请求
    迁移 )
    1)如前所述,每⼀台服务器负责⼀段,⼀致性哈希算法对于节点的增减都只需重定位环空间中的⼀⼩
    部分数据,具有较好的容错性和可扩展性。
    但是,⼀致性哈希算法在服务节点太少时,容易因为节点分部不均匀⽽造成数据倾斜问题。例如系统中
    只有两台服务器,其环分布如下,节点2只能负责⾮常⼩的⼀段,⼤量的客户端
    请求落在了节点1上,这就是数据(请求)倾斜问题
    2)为了解决这种数据倾斜问题,⼀致性哈希算法引⼊了虚拟节点机制,即对每⼀个服务节点计算多个
    哈希,每个计算结果位置都放置⼀个此服务节点,称为虚拟节点。
    具体做法可以在服务器ip或主机名的后⾯增加编号来实现。⽐如,可以为每台服务器计算三个虚拟节
    点,于是可以分别计算 “节点1的ip#1”、“节点1的ip#2”、“节点1的ip#3”、“节点2的ip#1”、“节点2的
    ip#2”、“节点2的ip#3”的哈希值,于是形成六个虚拟节点,当客户端被路由到虚拟节点的时候其实是被
    路由到该虚拟节点所对应的真实节点

    一致性Hash算法的代码

    普通hash算法

    /**
    * 普通Hash算法实现
    */
    public class GeneralHash {
    public static void main(String[] args) {
    // 定义客户端IP
    String[] clients = new String[]
    {"10.78.12.3","113.25.63.1","126.12.3.8"};
    // 定义服务器数量
    int serverCount = 5;// (编号对应0,1,2)
    // hash(ip)%node_counts=index
    //根据index锁定应该路由到的tomcat服务器
    for(String client: clients) {
    int hash = Math.abs(client.hashCode());
    int index = hash%serverCount;
    System.out.println("客户端:" + client + " 被路由到服务器编号为:" + index);
     }
     }
    }
    

    一致性hash算法不带虚拟节点

    public class ConsistentHashNoVirtual {
    public static void main(String[] args) {
    //step1 初始化:把服务器节点IP的哈希值对应到哈希环上
    // 定义服务器ip
    String[] tomcatServers = new String[]
    {"123.111.0.0","123.101.3.1","111.20.35.2","123.98.26.3"};
    SortedMap<Integer,String> hashServerMap = new TreeMap<>();
    for(String tomcatServer: tomcatServers) {
    // 求出每⼀个ip的hash值,对应到hash环上,存储hash值与ip的对应关系
    int serverHash = Math.abs(tomcatServer.hashCode());
    // 存储hash值与ip的对应关系
    hashServerMap.put(serverHash,tomcatServer);
     }
    //step2 针对客户端IP求出hash值
    // 定义客户端IP
    String[] clients = new String[]
    {"10.78.12.3","113.25.63.1","126.12.3.8"};
    for(String client : clients) {
    int clientHash = Math.abs(client.hashCode());
    //step3 针对客户端,找到能够处理当前客户端请求的服务器(哈希环上顺时针最
    近)
    // 根据客户端ip的哈希值去找出哪⼀个服务器节点能够处理()
    SortedMap<Integer, String> integerStringSortedMap =
    hashServerMap.tailMap(clientHash);
    if(integerStringSortedMap.isEmpty()) {
    // 取哈希环上的顺时针第⼀台服务器
    Integer firstKey = hashServerMap.firstKey();
    System.out.println("==========>>>>客户端:" + client + " 被
    路由到服务器:" + hashServerMap.get(firstKey));
     }else{
    Integer firstKey = integerStringSortedMap.firstKey();
    System.out.println("==========>>>>客户端:" + client + " 被
    路由到服务器:" + hashServerMap.get(firstKey));
     }
     }
     }
    }
    

    一致性hash算法带虚拟节点

    public class ConsistentHashWithVirtual {
    public static void main(String[] args) {
    //step1 初始化:把服务器节点IP的哈希值对应到哈希环上
    // 定义服务器ip
    String[] tomcatServers = new String[]
    {"123.111.0.0","123.101.3.1","111.20.35.2","123.98.26.3"};
    SortedMap<Integer,String> hashServerMap = new TreeMap<>();
    // 定义针对每个真实服务器虚拟出来⼏个节点
    int virtaulCount = 3;
    for(String tomcatServer: tomcatServers) {
    // 求出每⼀个ip的hash值,对应到hash环上,存储hash值与ip的对应关系
    int serverHash = Math.abs(tomcatServer.hashCode());
    // 存储hash值与ip的对应关系
    hashServerMap.put(serverHash,tomcatServer);
    // 处理虚拟节点
    for(int i = 0; i < virtaulCount; i++) {
    int virtualHash = Math.abs((tomcatServer + "#" + i).hashCode());
    hashServerMap.put(virtualHash,"----由虚拟节点"+ i + "映射过
    来的请求:"+ tomcatServer);
     }
     }
    //step2 针对客户端IP求出hash值
    // 定义客户端IP
    String[] clients = new String[]
    {"10.78.12.3","113.25.63.1","126.12.3.8"};
    for(String client : clients) {
    int clientHash = Math.abs(client.hashCode());
    //step3 针对客户端,找到能够处理当前客户端请求的服务器(哈希环上顺时针最
    近)
    // 根据客户端ip的哈希值去找出哪⼀个服务器节点能够处理()
    SortedMap<Integer, String> integerStringSortedMap =
    hashServerMap.tailMap(clientHash);
    if(integerStringSortedMap.isEmpty()) {
    // 取哈希环上的顺时针第⼀台服务器
    Integer firstKey = hashServerMap.firstKey();
    System.out.println("==========>>>>客户端:" + client + " 被
    路由到服务器:" + hashServerMap.get(firstKey));
     }else{
    Integer firstKey = integerStringSortedMap.firstKey();
    System.out.println("==========>>>>客户端:" + client + " 被
    路由到服务器:" + hashServerMap.get(firstKey));
     }
     }
     }
    }
    

    欢迎搜索关注本人与朋友共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】,以及总结的分类面试题https://github.com/zhendiao/JavaInterview

    file
    file

  • 相关阅读:
    Leetcode总结之Tree
    Leetcode总结之DFS
    Leetcode总结之Backtracking
    策略模式(设计模式_02)
    面向对象思想设计_计算器小程序(设计模式入门篇_01)
    Android GridView 滑动条设置一直显示状态
    dp暑假专题 训练记录
    dp入门 专题记录 2017-7-26
    dp问题 -挑战例题 2017-7-24
    贪心思维 专题记录 2017-7-21
  • 原文地址:https://www.cnblogs.com/zhendiao/p/14920368.html
Copyright © 2011-2022 走看看