一致性hash算法的具体实现

//在看如下代码时请确保你懂的一致性代码的原理 ,博文中采用 链表的方式来实现hash一致性算法
由一个链表来保持服务器的hashcode,并且该链表中的值都是递增的,这就相当于在2的30次方里分布了四个有序的机器,接下来将
数据的hashcode与四台服务器的hashcode从小到大依次进行对比 即可找到所分布的情况,需要注意的是当该数据大于所有机器的hashcode时
应该讲该数据置于第一台机器中(相当于构成环型) 集体实现如下

package com;

import com.algorithm.ArrayFalg;
import com.algorithm.HeadSort;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ConsistenHash {

    private ArrayList<Integer> sortHashs =new ArrayList<>(); //用链表来保存hashs值便于扩展

    private Map<Integer, String> hashServers = new HashMap<>(); //保存hash值与服务器的映射

    public void init(List<String> servers) {  //使用前 先确保初始化
        init((String[]) servers.toArray());

    }

    public String getServer(String node) {  
        if (sortHashs == null || sortHashs.isEmpty()) {
            return null;
        }
        int hashNode = getHash(node);
        int position = -1;
        for (int i = 0; i < sortHashs.size(); i++) {
            //找到第一个hash值大于该节点的服务器
            if (sortHashs.get(i) > position) {
                position = i;
                break;
            }
        }
        //没有服务器大于 则应非配给第一个
        if (position < 0) {
            position = 0;
        }
        return hashServers.get(sortHashs.get(position));

    }

    /**
     * 用于处理服务器所在位置
     * 并对他们进行排序
     *
     * @param servers
     */
    public void init(String[] servers) {
        int[] hashs = new int[servers.length];
        for (int i = 0; i < servers.length; i++) {
            int hashNode = getHash(servers[i]);
            hashServers.put(hashNode, servers[i]);
            hashs[i] = hashNode;
        }
        hashs = HeadSort.getArray(hashs, ArrayFalg.ORDER); //使用堆排序
        for (int hash : hashs) {
            sortHashs.add(hash);
        }

    }

    //假设某台机器坏掉

    public void downServer(String server) {
        int hashNode = getHash(server);
        if (sortHashs.contains(hashNode)) {
            sortHashs.remove(hashNode);
        }

    }

    //有机器加入 应该有序加入

    public void addServer(String server) {
        int hashNode = getHash(server);
        int position = 0;
        for (int i = 0; i < sortHashs.size(); i++) {
            //找到第一个hash值大于该节点的服务器
            if (hashNode > sortHashs.get(i)) {
                position++;
                continue;
            }
            break;
        }
        //当前hashNode为最小的一个

            sortHashs.add(position , hashNode);

        hashServers.put(hashNode, server);

    }

    /**
     * 使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,
     * 最终效果没区别 不建议使用对String的hashcode会使服务器过于密集
     */
    private static int getHash(String str) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < str.length(); i++)
            hash = (hash ^ str.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;
    }

    /**
     * 查找算法 用于确定节点应该放在哪个位置
     *
     * @param array
     * @param left
     * @param right
     * @param target
     * @return
     */
    private static int find(int array[], int left, int right, int target) {
        int pos = (left + right) / 2;
        if (right >= left) {
            if (target > array[pos]) {
                return find(array, pos + 1, right, target);
            } else if (target < array[pos]) {
                return find(array, left, pos - 1, target);
            } else {
                return pos;
            }
        }
        return pos;

    } 
  }
package com.algorithm;

public class HeadSort {

    public static int[] getArray(int[] array,ArrayFalg arrayFalg) {
        if(array==null){
            return null;
        }
        if(arrayFalg ==ArrayFalg.REVERSE) {
            for (int i = array.length - 1; i > 0; i--) {
                heapMinAdjust(array, i);
                swap(array, 0, i);
            }
        }else{
            for (int i = array.length - 1; i > 0; i--) {
                heapMaxAdjust(array, i);
                swap(array, 0, i);
            }
        }
        return array;
    }
    //构建最小堆
    public static void minHeap(int[] array, int start, int end) {
        int j = 2 * start + 1; //左做节点
        int tmp = array[start];
        int length = end;
        while (j <= length) {
            if (j + 1 <= length && array[j + 1] < array[j]) {
                j++;
            }
            if (array[j] < tmp) {
                array[start] = array[j];
                start = j;
                j = 2 * start + 1;
            } else {
                break;
            }
        }
        array[start] = tmp;
    }

    //构建最大堆
    public static void maxHeap(int[] array, int start, int end) {
        int j = 2 * start + 1; //左做节点
        int tmp = array[start];
        int length = end;
        while (j <= length) {
            if (j + 1 <= length && array[j + 1] > array[j]) {
                j++;
            }
            if (array[j] > tmp) {
                array[start] = array[j];
                start = j;
                j = 2 * start + 1;
            } else {
                break;
            }
        }
        array[start] = tmp;
    }

    /**
     * 使用的是堆排序,每次出最小放在数组末端,因此t表示未处理的最后下标
     *
     * @param array 目标数组
     * @param end   为处理数据的最后下标
     */
    public static void heapMinAdjust(int[] array, int end) {
        for (int j = end / 2; j >= 0; j--) {
            minHeap(array, j, end);
        }
    }

    public static void heapMaxAdjust(int[] array, int end) {
        for (int j = end / 2; j >= 0; j--) {
            maxHeap(array, j, end);
        }
    }


    public static void swap(int[] array, int i, int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

}

猜你喜欢

转载自blog.csdn.net/qq_32459653/article/details/81149688
今日推荐