zoukankan      html  css  js  c++  java
  • 一致性哈希java实现

    值得注意的点

    1. 哈希函数的选择
    • murmur哈希函数
      该函数是非加密型哈希,性能高,且发生哈希碰撞的概率据说很低
    • md5
    • SHA
    • 可以选择guava包,提供了丰富的哈希函数的API
    1. 支持虚拟节点+加权,因为不同的节点可能资源配置不同,加权可以使负载均衡最大化,虚拟节点,可以降低某个节点出现问题后对整个哈希环的冲击

    2. 考虑到不同场景用来作哈希的key可能不一样,所以提供一个包装类Node,可以自定义key,且可以自定义权重

    3. 安全问题,添加节点和删除节点是需要重建哈希环,此处要考虑并发情况的发生(此处暂未实现),一般情况下只需初始化一次即可。

    4. 哈希后的取值,本处为了通用采用String类型,可以针对特殊场景作优化,个人认为只有最适合的,没有最好的

    实现

    1. 包装类node
    public final class Node<T> {
    
        public static final int DEFAULT_WEIGHT = 1;
    
        private T target;
        private String key;
        private int weight = DEFAULT_WEIGHT;
    
        public Node(T target) {
            this.target = target;
            this.key = target.toString();
        }
    
        public Node(T target, String key) {
            this.target = target;
            this.key = key;
        }
    
        public Node(T target, String key, int weight) {
            this.target = target;
            this.key = key;
            this.weight = weight;
        }
    
        public T getTarget() {
            return target;
        }
    
        public void setTarget(T target) {
            this.target = target;
        }
    
        public String getKey() {
            return key;
        }
    
        public void setKey(String key) {
            this.key = key;
        }
    
        public int getWeight() {
            return weight;
        }
    
        public void setWeight(int weight) {
            this.weight = weight;
        }
    }
    
    1. 一致性哈希
    import com.google.common.hash.HashFunction;
    import com.google.common.hash.Hashing;
    
    import java.nio.charset.Charset;
    import java.util.*;
    
    /**
     * 一致性哈希
     * @param <T>
     */
    public class ConsistentHash<T> {
    
        //哈希函数
        private HashFunction hashFunction = Hashing.murmur3_32();
        //哈希环
        private TreeMap<String, Node<T>> nodeMappings = new TreeMap<>();
        //虚拟节点数
        private int replicas = 160;
        //真实节点
        private List<Node<T>> realNodes;
    
        public ConsistentHash(HashFunction hashFunction, List<Node<T>> realNodes, int replicas) {
            this.hashFunction = hashFunction;
            this.realNodes = realNodes;
            this.replicas = replicas;
        }
    
        public ConsistentHash(HashFunction hashFunction, List<Node<T>> realNodes) {
            this.hashFunction = hashFunction;
            this.realNodes = realNodes;
        }
    
        public ConsistentHash(List<Node<T>> realNodes, int replicas) {
            this.realNodes = realNodes;
            this.replicas = replicas;
        }
    
        public ConsistentHash(List<Node<T>> realNodes) {
            this.realNodes = realNodes;
        }
    
        /**
         * 初始化哈希环
         */
        public void init(){
            realNodes.forEach(node -> {
                for (int i = 0; i < replicas*node.getWeight(); i++) {
                    StringBuilder sb = new StringBuilder(node.getKey());
                    sb.append(i);
                    nodeMappings.put(hashCode(sb.toString()), node);
                }
            });
        }
    
        public String hashCode(String key){
            return hashFunction.hashString(key, Charset.defaultCharset()).asBytes().toString();
        }
    
        public Node<T> getNode(String key){
            SortedMap<String, Node<T>> tailMap = nodeMappings.tailMap(hashCode(key));
            if(tailMap.isEmpty()){
                return nodeMappings.get(nodeMappings.firstKey());
            }
            return tailMap.get(tailMap.firstKey());
        }
    
        public static void main(String[] args) {
            List<Node<String>> realNodes = Arrays.asList(new Node("127.0.0.1"),new Node("192.168.4.175"),new Node("192.168.3.175"), new Node("172.147.0.101"));
            ConsistentHash consistentHash = new ConsistentHash(Hashing.md5(), realNodes);
            consistentHash.init();
    
            List<Node> one = new ArrayList<>();
            List<Node> two = new ArrayList<>();
            List<Node> three = new ArrayList<>();
            List<Node> four = new ArrayList<>();
            for (int i = 0; i <10000 ; i++) {
                Node<String> node = consistentHash.getNode("node"+i);
                if(node.getKey().equals("127.0.0.1")){
                    one.add(node);
                }
                if(node.getKey().equals("192.168.4.175")){
                    two.add(node);
                }
                if(node.getKey().equals("192.168.3.175")){
                    three.add(node);
                }
                if(node.getKey().equals("172.147.0.101")){
                    four.add(node);
                }
            }
            System.out.println(one.size());
            System.out.println(two.size());
            System.out.println(three.size());
            System.out.println(four.size());
        }
    
  • 相关阅读:
    多校 4686 Arc of Dream hdu 矩阵解
    关于wind7重新安装系统后,连接mysql的问题
    hadoop学习之ZooKeeper
    viewDidLoad、viewDidUnload、viewWillAppear、viewDidAppear、viewWillDisappear 和 -viewDidDisappear的区别和使用
    python处理中文字符
    linux配置本地tomcat应用80端口转发
    基于JVM规范的并发编程解决方案
    poj 3211 Washing Clothes(背包)
    hdu 4687 带花树匹配
    SQLiteLog (1) no such Column:
  • 原文地址:https://www.cnblogs.com/warking/p/7842976.html
Copyright © 2011-2022 走看看