zoukankan      html  css  js  c++  java
  • 一致性hash(整理版)

    简单解释:

    简单解释一致性hash的原理:网上通篇都是用服务器做的举例,我这里也如此,主要是便于理解。

    通常:有N个客户端请求服务器,假设有M台web服务器,通常为了均衡访问会进行N%M的取模,然后分配到不同的缓存服务器访问。问题是一旦缓存服务器增加或减少时缓存的命中率被打乱,因为取模发生了变化。例A的访问分配到了M1上,假设服务器增减则有可能会被分配到M3上(M3为举例),那么M1上的原有缓存失效,M3需要重新建立A访问的缓存。

    一致性Hash:有N个客户端请求服务器,假设有M台web服务器,把其中一个请求做HASH,M台服务器也做HASH,采用Sortedmap的tailMap特性,检索顺时针最近的一台服务器作为缓存服务器;

    例:其中一个请求HASHCODE=254,M台服务器HASH后分别为1、58、648...(数字为举例),那么通过Sortedmap的tailMap特性可以找到648以及后面的服务器,则把最近的648作为缓存服务器。当然 如果tailMap找到的为NULL,则从Sortedmap的第一条key作为缓存服务器(保证map是一个环装)

    简单代码:

    完整代码示意-摘自互联网的代码(整理后),可以参考。

    package com.yiibai;
    
    import java.util.*;
    
    public class TreeMapDemo {
       public static void main(String[] args) {
          // creating maps 
          TreeMap<Integer, String> treemap = new TreeMap<Integer, String>();
          SortedMap<Integer, String> treemapincl = new TreeMap<Integer, String>();
                
          // populating tree map
          treemap.put(2, "two");
          treemap.put(1, "one");
          treemap.put(3, "three");
          treemap.put(6, "six");
          treemap.put(5, "five");      
          
          System.out.println("Getting tail map");
          treemapincl=treemap.tailMap(3);
          System.out.println("Tail map values: "+treemapincl);      
       }    
    }

    完整代码示意-摘自互联网的代码(整理后),可以参考。

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    import org.apache.commons.codec.digest.DigestUtils;
    
    public class VNode  {
        private SortedMap<Integer, String> serverNodeMap = null;
        
        private final static int VIRTUAL_NODE_NUMBER = 5;
        
        
        public void getServerNodeWithoutVirtualNode(List<String> servers)
        {
            serverNodeMap = new TreeMap<Integer, String>();
            for (String string : servers) 
            {
                serverNodeMap.put(hash(string), string);
            }
        }
        
        public void getServerNodeWithVirtualNode(List<String> servers) 
        {
            serverNodeMap = new TreeMap<Integer, String>();
            for (String string : servers) 
            {
                for (int i = 0; i < VIRTUAL_NODE_NUMBER; i++) 
                {
                    String virtualNodeName = string + ":" + i;
                    serverNodeMap.put(hash(virtualNodeName), string);
                }
            }
        }
        
        public String getServerName(String data) 
        {
            int dataHash = hash(data);
            SortedMap<Integer, String> subMap = serverNodeMap.tailMap(dataHash);
            int serverHash = 0;
            if (subMap == null || subMap.size() == 0) 
            {
                serverHash = serverNodeMap.firstKey();
            }
            else 
            {
                serverHash = subMap.firstKey();
            }
            
            String serverName = serverNodeMap.get(serverHash);
            return serverName;
            
        }
        
        
        /**
         * hash计算,这里使用md5后取hashcode,这个md5需要依赖apache的codec包
         * @param str
         * @return
         */
        public int hash(String str) 
        {
            //System.out.println(str+"的hashcode="+DigestUtils.md5Hex(str).hashCode());
            return DigestUtils.md5Hex(str).hashCode();
        }
        
        public static void main(String[] args) 
        {
            List<String> servers = new ArrayList<String>();
            servers.add("192.168.1.1");
            servers.add("192.168.1.2");
            servers.add("192.168.1.3");
            servers.add("192.168.1.4");
            servers.add("192.168.1.5");
            servers.add("192.168.1.6");
            
            List<String> datas = new ArrayList<String>();
            datas.add("A");
            datas.add("B");
            datas.add("C");
            datas.add("D");
            datas.add("E");
            datas.add("F");
            datas.add("G");
            datas.add("H");
            datas.add("I");
            
            VNode consistentHash = new VNode();
            System.out.println("没有虚拟节点的情况:");
            consistentHash.getServerNodeWithoutVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            System.out.println("有虚拟节点的情况:");
            consistentHash.getServerNodeWithVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            
            servers.add("192.168.1.7");
            System.out.println("增加第一个一个节点后:");
            System.out.println("没有虚拟节点的情况:");
            consistentHash.getServerNodeWithoutVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            System.out.println("有虚拟节点的情况:");
            consistentHash.getServerNodeWithVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            
            servers.remove(0);
            System.out.println("移除第一个一个节点后:");
            System.out.println("没有虚拟节点的情况:");
            consistentHash.getServerNodeWithoutVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            System.out.println("有虚拟节点的情况:");
            consistentHash.getServerNodeWithVirtualNode(servers);
            consistentHash.printDataAndServerNode(servers, datas, consistentHash);
            
        }
    
        public void printDataAndServerNode(List<String> servers, List<String> datas,VNode consistentHash) 
        {
            Map<String, String> result = new HashMap<String, String>();
            for (String data : datas) 
            {
                String serverName = consistentHash.getServerName(data);
                if (!result.containsKey(serverName)) 
                {
                    result.put(serverName, data);
                }
                else
                {
                    result.put(serverName, result.get(serverName) + "," + data);
                }
            }
            
            for (Entry<String, String> entry : result.entrySet()) 
            {
                System.out.println(entry.getKey()+":"+entry.getValue());
            }
        }
    }
  • 相关阅读:
    cisco telnet(转载)
    华为bfd配置步骤
    cisco ssh实验--附带配置脚本-2019.11.19
    远程设备管理opendx平台搭建-server,agent以及front实际搭建
    远程设备管理opendx平台搭建-appium和adb的安装
    华为交换机sflow配置
    华为交换机netstream配置
    centos6虚拟机复制后修改网卡
    docker基本操作
    esxi 6 添加硬盘、网卡
  • 原文地址:https://www.cnblogs.com/fan-yuan/p/10408337.html
Copyright © 2011-2022 走看看