2.一、Node類,每一個Node表明集羣裏面的一個節點或者具體說是某一臺物理機器;java
package consistencyhash; import lombok.Getter; import lombok.RequiredArgsConstructor; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author xfyou * @date 2019/9/2 */ @Getter @RequiredArgsConstructor public class Node { private final String domain; private final String ip; private final Map<String, Object> data = new ConcurrentHashMap<>(); public <T> void put(String key, T value) { data.put(key, value); } public void remove(String key) { data.remove(key); } public <T> T get(String key) { return (T) data.get(key); } }
2.二、 AbstractCluster,cluster抽象類,集羣抽象類;node
package consistencyhash; import java.util.ArrayList; import java.util.List; /** * @author xfyou * @date 2019/9/2 */ public abstract class AbstractCluster { protected final List<Node> nodes; public AbstractCluster() { this.nodes = new ArrayList<>(); } public abstract void addNode(Node node); public abstract void removeNode(Node node); public abstract Node get(String key); }
2.三、Cluster類,集羣類,一致性hash算法的具體實現類算法
package consistencyhash; import java.util.SortedMap; import java.util.TreeMap; import java.util.stream.IntStream; /** * @author xfyou * @date 2019/9/2 */ public class ConsistencyHashCluster extends AbstractCluster { private final SortedMap<Long, Node> virNodes = new TreeMap<>(); private static final int VIR_NODE_COUNT = 160; private static final String SPLIT = "#"; @Override public void addNode(Node node) { this.nodes.add(node); IntStream.range(0, VIR_NODE_COUNT).forEach(index -> { long hash = System.identityHashCode((node.getIp() + SPLIT + index).intern()); virNodes.put(hash, node); }); } @Override public void removeNode(Node node) { nodes.removeIf(o -> node.getIp().equals(o.getIp())); IntStream.range(0, VIR_NODE_COUNT).forEach(index -> { long hash = System.identityHashCode((node.getIp() + SPLIT + index).intern()); virNodes.remove(hash); }); } @Override public Node get(String key) { long hash = System.identityHashCode(key); SortedMap<Long, Node> subMap = hash >= virNodes.lastKey() ? virNodes.tailMap(0L) : virNodes.tailMap(hash); if (subMap.isEmpty()) { return virNodes.get(virNodes.firstKey()); } System.out.println("hash=" + hash + ",subMap.firstKey=" + subMap.firstKey()); Node node = subMap.get(subMap.firstKey()); return node; } }
2.四、Test類,測試類緩存
package consistencyhash; import java.util.stream.IntStream; /** * @author xfyou * @date 2019/9/2 */ public class Test { private static final int DATA_CONT = 10; private static final String PRE_KEY = "PRE_KEY"; public static void main(String[] args) { AbstractCluster cluster = new ConsistencyHashCluster(); cluster.addNode(new Node("n1.test.info", "192.168.0.1")); cluster.addNode(new Node("n2.test.info", "192.168.0.2")); cluster.addNode(new Node("n3.test.info", "192.168.0.3")); IntStream.range(0, DATA_CONT).forEach(index -> { Node node = cluster.get((PRE_KEY + index).intern()); node.put((PRE_KEY + index).intern(), "cached_data"); }); System.out.println("數據分佈狀況:"); cluster.nodes.forEach(node -> { System.out.println("IP:" + node.getIp() + ",數據量:" + node.getData().size()); }); long hitCount = IntStream.range(0, DATA_CONT).filter(index -> cluster.get((PRE_KEY + index).intern()).get((PRE_KEY + index).intern()) != null).count(); System.out.println("hitCount=" + hitCount); System.out.println("緩存命中率:" + hitCount * 1f / DATA_CONT); } }