测试代码:
public class UserTest { private static final Integer NODE_COUNT = 6; private static final Integer VIRTUAL_NODE_COUNT = 200; private static final Integer EXE_TIMES = 100; public static void main(String[] args) throws IOException { UserTest test = new UserTest(); //初始化节点 List<Node> allNodes = test.getNodes(NODE_COUNT); KetamaNodeLocator locator = new KetamaNodeLocator(allNodes, HashAlgorithm.KETAMA_HASH, VIRTUAL_NODE_COUNT); //初始化所有的userid List<String> allKeys = test.getAllStrings(); //写userid到文件中,查看写的分布情况 // for (String key : allKeys) { // Node node = locator.getPrimary(key); // // File file = new File(node.getUrl()); // if (!file.getParentFile().exists()) { // file.getParentFile().mkdirs(); // } // if (!file.exists()) { // file.createNewFile(); // } // FileWriter writer = new FileWriter(file.getAbsolutePath(), true); // writer.write(key + System.getProperty("line.separator")); // writer.close(); // } //添加一个节点6,将1中的数据复制到6中,验证数据是否都能找到 // for (String key : allKeys) { // Node node = locator.getPrimary(key); // // File file = new File(node.getUrl()); // BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); // String line = null; // boolean find = false; // while ((line = reader.readLine()) != null) { // if (key.equals(line)) { // find = true; // } // } // if (!find) { // System.out.println("name:" + node.getName() + ",value=" + key); // } //// else if (node.getName().equals("node6")) { //// System.out.println("value=" + key); //// } // } System.out.println(HashAlgorithm.KETAMA_HASH.hash(HashAlgorithm.KETAMA_HASH.md5("userid-3"), 0)); } /** * Gets the mock node by the material parameter * * @param nodeCount * the count of node wanted * @return * the node list */ private List<Node> getNodes(int nodeCount) { List<Node> nodes = new ArrayList<Node>(); for (int k = 1; k <= nodeCount; k++) { String name = "node" + k; String url = "D:\\" + "node" + k + ".txt"; Node node = new Node(name, url); nodes.add(node); } return nodes; } /** * All the keys */ private List<String> getAllStrings() { List<String> allStrings = new ArrayList<String>(EXE_TIMES); for (int i = 0; i < EXE_TIMES; i++) { allStrings.add("userid-" + i); } return allStrings; } }
测试发现,不是某个节点的数据被映射到node6中,而是好几个,如果是做数据迁移的话,麻烦就不小了。
对于缓存来说,增加虚拟节点确实能带来好处,因为他只关心命中率,对于数据一致性要求不高。但是对于存储系统来说,就要考虑
数据迁移的问题,如果采用了虚拟节点,那么一个物理节点就存在多个虚拟节点。如果增加一台机器,它又会对应多个虚拟机点。
当再次对所有节点重新分配,需要将所有新增的虚拟节点的顺时针下一个虚拟节点统计出来,然后将统计出来的对应的所有物理节点的数据
迁移到新增的物理节点上。这也是个大的工作量。
又或者是我理解错了?当加一台物理节点时,不给他分配虚拟节点,只查询比他大的最小的虚拟节点,然后找出该虚拟节点的物理节点,将此物理节点的数据
迁移到新物理节点上,但这是否新的物理节点有些浪费呢?有待研究