//在看如下代码时请确保你懂的一致性代码的原理 ,博文中采用 链表的方式来实现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; } }