java实现hash一致性算法

package hash;

import hash.Shard.Node;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

@SuppressWarnings("hiding")
public class Shard<Node> { // S类封装了机器节点的信息 ,如name、password、ip、port等

    static private TreeMap<Long, Node> nodes; // 虚拟节点到真实节点的映射
    static private TreeMap<Long, Node> treeKey; //key到真实节点的映射
    static private List<Node> shards = new ArrayList<Node>(); // 真实机器节点
    private final int NODE_NUM = 100; // 每个机器节点关联的虚拟节点个数
    boolean flag = false;

    @SuppressWarnings("static-access")
    public Shard(List<Node> shards) {
        super();
        this.shards = shards;
        init();
    }

    public static void main(String[] args) {
        Node s1 = new Node("s1", "192.168.1.1");
        Node s2 = new Node("s2", "192.168.1.2");
        Node s3 = new Node("s3", "192.168.1.3");
        Node s4 = new Node("s4", "192.168.1.4");
        shards.add(s1);
        shards.add(s2);
        shards.add(s3);
        shards.add(s4);
        Shard<Node> sh = new Shard<Node>(shards);
        System.out.println("添加客户端,一开始有4个主机,分别为s1,s2,s3,s4,每个主机有100个虚拟主机:");
        sh.keyToNode("101客户端");
        sh.keyToNode("102客户端");
        sh.keyToNode("103客户端");
        sh.keyToNode("104客户端");
        sh.keyToNode("105客户端");
        sh.keyToNode("106客户端");
        sh.keyToNode("107客户端");
        sh.keyToNode("108客户端");
        sh.keyToNode("109客户端");
        sh.deleteS(s4);
        sh.addS(s4);
        System.out.println("最后的客户端到主机的映射为:");
        printKeyTree();
    }

    /**
     * 打印真实节点的映射
     */
    public static void printKeyTree(){
        for(Iterator<Long> it = treeKey.keySet().iterator();it.hasNext();){
            Long lo = it.next();
            System.out.println("hash("+lo+")连接到主机->"+treeKey.get(lo));
        }
    }

    /**
     * 生成虚拟节点的映射
     */
    private void init() { // 初始化一致性hash环
        nodes = new TreeMap<Long, Node>();
        treeKey = new TreeMap<Long, Node>();
        for (int i = 0; i != shards.size(); ++i) { // 每个真实机器节点都需要关联虚拟节点
            final Node shardInfo = shards.get(i);
            for (int n = 0; n < NODE_NUM; n++)
            {
                // 一个真实机器节点关联NODE_NUM个虚拟节点
                nodes.put(hash("SHARD-" + shardInfo.name + "-NODE-" + n), shardInfo);
            }
        }
    }
    //增加一个主机
    private void addS(Node s) {
        System.out.println("增加主机"+s+"的变化:");
        for (int n = 0; n < NODE_NUM; n++) {
            addS(hash("SHARD-" + s.name + "-NODE-" + n), s);
        }
    }

    //添加一个虚拟节点进环形结构,lg为虚拟节点的hash值
    public void addS(Long lg,Node s){
        SortedMap<Long, Node> tail = nodes.tailMap(lg);
        SortedMap<Long,Node>  head = nodes.headMap(lg);
        SortedMap<Long, Node> between;
        if(head.size()==0){
            between = treeKey.tailMap(nodes.lastKey());
        }else{
            Long begin = head.lastKey();
            between = treeKey.subMap(begin, false, lg, true);
        }
        nodes.put(lg, s);
        for(Iterator<Long> it=between.keySet().iterator();it.hasNext();){
            Long lo = it.next();
            treeKey.put(lo, nodes.get(lg));
            System.out.println("hash("+lo+")改变到->"+tail.get(tail.firstKey()));
        }
    }

    //删除真实节点是s
    public void deleteS(Node s){
        if(s==null){
            return;
        }
        System.out.println("删除主机"+s+"的变化:");
        for(int i=0;i<NODE_NUM;i++){
            //定位s节点的第i的虚拟节点的位置
            SortedMap<Long, Node> tail = nodes.tailMap(hash("SHARD-" + s.name + "-NODE-" + i));
            SortedMap<Long,Node>  head = nodes.headMap(hash("SHARD-" + s.name + "-NODE-" + i));
            SortedMap<Long, Node> between;
            if(head.size()==0){
                between = treeKey.tailMap(nodes.lastKey());
            }else{
                Long begin = head.lastKey();
                Long end = tail.firstKey();
                between = treeKey.subMap(begin, false, end, true);//在s节点的第i个虚拟节点的所有key的集合
            }
            nodes.remove(tail.firstKey());//从nodes中删除s节点的第i个虚拟节点
            for(Iterator<Long> it = between.keySet().iterator();it.hasNext();){
                Long lo = it.next();
                if (tail.size() == 0) {
                    // 如果是尾节点,则关联到首接点上
                    treeKey.put(lo, nodes.firstEntry().getValue());
                    System.out.println("hash("+lo+")改变到->"+nodes.firstEntry().getValue());
                } else {
                    treeKey.put(lo, tail.get(tail.firstKey()));
                    System.out.println("hash("+lo+")改变到->"+tail.get(tail.firstKey()));
                }
            }
        }

    }

    //映射key到真实节点
    public void keyToNode(String key){
        Long hashKey = hash(key);
        SortedMap<Long, Node> tail = nodes.tailMap(hashKey); // 沿环的顺时针找到一个虚拟节点
        // 如果是尾节点
        if (tail.size() == 0) {
            // 映射节点为首节点
            treeKey.put(hashKey, nodes.firstEntry().getValue());
            System.out.println(key+"(hash: "+hashKey+")连接到主机->"+nodes.firstEntry().getValue());
            return;
        }
        treeKey.put(hashKey, tail.get(tail.firstKey()));
        System.out.println(key+"(hash:"+hashKey+")连接到主机->"+tail.get(tail.firstKey()));
    }

    /**
     *  MurMurHash算法,是非加密HASH算法,性能很高,
     *  比传统的CRC32,MD5,SHA-1(这两个算法都是加密HASH算法,复杂度本身就很高,带来的性能上的损害也不可避免)
     *  等HASH算法要快很多,而且据说这个算法的碰撞率很低.
     *  http://murmurhash.googlepages.com/
     */
    private static Long hash(String key) {
        ByteBuffer buf = ByteBuffer.wrap(key.getBytes());
        int seed = 0x1234ABCD;
        ByteOrder byteOrder = buf.order();
        buf.order(ByteOrder.LITTLE_ENDIAN);
        long m = 0xc6a4a7935bd1e995L;
        int r = 47;
        long h = seed ^ (buf.remaining() * m);
        long k;
        while (buf.remaining() >= 8) {
            k = buf.getLong();
            k *= m;
            k ^= k >>> r;
            k *= m;
            h ^= k;
            h *= m;
        }
        if (buf.remaining() > 0) {
            ByteBuffer finish = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN);
            finish.put(buf).rewind();
            h ^= finish.getLong();
            h *= m;
        }
        h ^= h >>> r;
        h *= m;
        h ^= h >>> r;
        buf.order(byteOrder);
        return h;
    }

    static class Node{
        String name;
        String ip;
        public Node(String name,String ip) {
            this.name = name;
            this.ip = ip;
        }
        @Override
        public String toString() {
            return this.name+"-"+this.ip;
        }
    }
}
时间: 2024-10-13 19:20:12

java实现hash一致性算法的相关文章

hash一致性算法

转自:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,初衷和CARP十分类似.一致性哈希修正了CARP使用的简 单哈希算法带来的问题,使得分布式哈希(DHT)可以在P2P环境中真正得到应用. 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 1.平衡性(Balance)

Hash一致性算法底层原理

大纲 Hash取余算法 判定哈希算法好坏的四个定义 一致性Hash算法的两大设计 Hash取余算法 hash(Object.key)%N,hash值随Object.key.N的变化而变化. 如果有节点(集群中节点增减太正常)发生变化,几乎重新分配,意味着所有已经分配好的数据都要迁移到新的节点上. 一致性Hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 1.平衡性(Balance):平衡性是指哈希的结果能够尽可能分布在所有的缓冲(Cache)中去,这样可以使得所有的缓冲

Raft一致性算法

转自 http://blog.csdn.net/cszhouwei/article/details/38374603 Why Not Paxos Paxos算法是莱斯利·兰伯特(LeslieLamport,就是 LaTeX 中的”La”,此人现在在微软研究院)于1990年提出的一种基于消息传递的一致性算法.由于算法难以理解起初并没有引起人们的重视,使Lamport在八年后1998年重新发表到ACM Transactions on Computer Systems上(The Part-TimePa

分布式一致性算法梳理

分布式一致性算法主流方案:2PC.3PC.leader/follower.paxos 一致性有两种场景: 1.多份相同的数据,在一处修改,保证多份一致 2.一个业务变更多份不同的数据,要保持一致,要成功都成功,要失败都失败 产生不一致的原因: 1.异常操作导致不成功 2.网络分区 3.应用故障 两阶段提交(2PC) 将事务的提交分为准备和提交两个阶段来达成一致性的算法,主要用于事务管理.分布式一致性,两阶段提交需要在更新发起者和参与者中间加一个协调者的角色.具体步骤如下: 1.变更者发起变更申请

一致性算法中的节点下限(转)

在众多的分布式一致性算法中,经常需要通过节点的数量满足某种规则来保证算法的正确性,比如Paxos算法,依赖一个”多数派“ 节点的工作的正确性.这类算法的共同目标是容许尽量多的节点失败但又不影响算法的正确性”. 这类问题本质上都抽象为数学上集合之间的逻辑关系,下面我们便从集合的性质入手讨论,为此先引入两个问题: 假设N为一非空结合,n为集合的元素数,M1,M2,...,Mm为N的m个子集,其元素数分别为n1,n2,...,nm,则: 求得M1∩M2∩...∩Mn≠Φ的条件 求得M1∩M2∩...∩

一致性算法--Paxos

分布式一致性算法--Paxos Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法.Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致.在工程实践意义上来说,就是可以通过Paxos实现多副本一致性,分布式锁,名字管理,序列号分配等.比如,在一个分布式数据库系统中,如果各节点的初始状态一致,每个节点执行相同的操作序列,那么他们最后能得到一个一致的状态.为保证每个节点执行相同的命令序列,需要在每一条指令上执行一个“一致性算法”

Java中的经典算法之冒泡排序(Bubble Sort)

Java中的经典算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后.然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后.重复第一趟步骤,直至全部排序完成. 举例说明:要排序数组:int[] arr={6,3,8,2,9,1}; 第一趟排序: 第一次排序:6和3比较,6大于3,交换位置:  

Lua中table内建排序与C/C++/Java/php/等内排序算法的排序效率比较

Lua这类脚本语言在处理业务逻辑作为配置文件的时候方便省事 但是在大量需要 运算的地方就显得略微不足   按照 Lua内建排序算法 对比C/C++ PHP Java等的快速排序算法进行一下比较. 快速排序算法是基于冒泡排序,优化而来,时间复杂度T(n)=O(nLog2n)  ,可见内部采用了二分策略 . 发现在LuaIDE LDT下直接运行效率要比 通过C++加载运行Lua脚本效率高的多  拿500W个数据排序 来说  ,脚本如下 同样的排序脚本Lua解释器的内置排序算法在LDT下,运行速度比通

一致性问题和Raft一致性算法——一致性问题是无法彻底解决的,可以说一个分布式系统可靠性达到99.99…%,但不能说它达到了100%

一致性问题 一致性算法是用来解决一致性问题的,那么什么是一致性问题呢? 在分布式系统中,一致性问题(consensus problem)是指对于一组服务器,给定一组操作,我们需要一个协议使得最后它们的结果达成一致. 更详细的解释就是,当其中某个服务器收到客户端的一组指令时,它必须与其它服务器交流以保证所有的服务器都是以同样的顺序收到同样的指令,这样的话所有的 服务器会产生一致的结果,看起来就像是一台机器一样. 实际生产中一致性算法需要具备以下属性: safety:即不管怎样都不会返回错误的结果