关于一致性hash的讲解有很多,也不难理解,具体可以翻看其他人写的这个文章
【转】http://limitlee.iteye.com/blog/1961385
自己动手写了一个java的实现过程,记录一下。
class="java" name="code">package com.xjw.consistent.hash; 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 java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.apache.commons.codec.digest.DigestUtils; public class ConsistentHash { private SortedMap<Integer, String> serverNodeMap = null; private final static int VIRTUAL_NODE_NUMBER = 5; public void getServerNodeWithoutVirtualNode(List<String> servers) { serverNodeMap = new TreeMap<>(); for (String string : servers) { serverNodeMap.put(hash(string), string); } } public void getServerNodeWithVirtualNode(List<String> servers) { serverNodeMap = new TreeMap<>(); 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) { return DigestUtils.md5Hex(str).hashCode(); } public static void main(String[] args) { List<String> servers = new ArrayList<>(); 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<>(); datas.add("河南"); datas.add("山东"); datas.add("天津"); datas.add("北京"); datas.add("上海"); datas.add("广州"); datas.add("乌海"); datas.add("武汉"); datas.add("合肥"); datas.add("长沙"); ConsistentHash consistentHash = new ConsistentHash(); 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, ConsistentHash consistentHash) { Map<String, String> result = new HashMap<>(); 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()); } } }
?
?输出结果为:
没有虚拟节点的情况:
192.168.1.1:河南,山东,广州
192.168.1.3:天津,合肥,长沙
192.168.1.4:北京,上海,乌海
192.168.1.6:武汉
有虚拟节点的情况:
192.168.1.1:上海
192.168.1.3:河南,天津,广州
192.168.1.2:山东,北京,乌海,合肥
192.168.1.5:武汉
192.168.1.6:长沙
移除第一个一个节点后:
没有虚拟节点的情况:
192.168.1.3:河南,山东,天津,广州,合肥,长沙
192.168.1.4:北京,上海,乌海
192.168.1.6:武汉
有虚拟节点的情况:
192.168.1.3:河南,天津,广州
192.168.1.2:山东,北京,乌海,合肥
192.168.1.5:上海,武汉
192.168.1.6:长沙