| ConsistentHashSelector ,是 ConsistentHashLoadBalance 的内部类,一致性哈希选择器,基于 Ketama  算法。 /**  * 虚拟节点与 Invoker 的映射关系  */ private final TreeMap<Long, Invoker<T>> virtualInvokers; /**  * 每个Invoker 对应的虚拟节点数  */ private final int replicaNumber; /**  * 定义哈希值  */ private final int identityHashCode; /**  * 取值参数位置数组  */ private final int[] argumentIndex;  1: ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {  2: this.virtualInvokers = new TreeMap<Long, Invoker<T>>();  3: // 设置 identityHashCode  4: this.identityHashCode = identityHashCode;  5: URL url = invokers.get(0).getUrl();  6: // 初始化 replicaNumber  7: this.replicaNumber = url.getMethodParameter(methodName, "hash.nodes", 160);  8: // 初始化 argumentIndex  9: String[] index = Constants.COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, "hash.arguments", "0"));  10: argumentIndex = new int[index.length];  11: for (int i = 0; i < index.length; i++) {  12: argumentIndex[i] = Integer.parseInt(index[i]);  13: }  14: // 初始化 virtualInvokers  15: for (Invoker<T> invoker : invokers) {  16: String address = invoker.getUrl().getAddress();  17: // 每四个虚拟结点为一组,为什么这样?下面会说到  18: for (int i = 0; i < replicaNumber / 4; i++) {  19: // 这组虚拟结点得到惟一名称  20: byte[] digest = md5(address + i);  21: // Md5是一个16字节长度的数组,将16字节的数组每四个字节一组,分别对应一个虚拟结点,这就是为什么上面把虚拟结点四个划分一组的原因  22: for (int h = 0; h < 4; h++) {  23: // 对于每四个字节,组成一个long值数值,做为这个虚拟节点的在环中的惟一key  24: long m = hash(digest, h);  25: virtualInvokers.put(m, invoker);  26: }  27: }  28: }  29: } public Invoker<T> select(Invocation invocation) {  // 基于方法参数,获得 KEY  String key = toKey(invocation.getArguments());  // 计算 MD5 值  byte[] digest = md5(key);  // 计算 KEY 值  return selectForKey(hash(digest, 0)); } private String toKey(Object[] args) {  StringBuilder buf = new StringBuilder();  for (int i : argumentIndex) {  if (i >= 0 && i < args.length) {  buf.append(args[i]);  }  }  return buf.toString(); } private Invoker<T> selectForKey(long hash) {  // 得到大于当前 key 的那个子 Map ,然后从中取出第一个 key ,就是大于且离它最近的那个 key  Map.Entry<Long, Invoker<T>> entry = virtualInvokers.tailMap(hash, true).firstEntry();  // 不存在,则取 virtualInvokers 第一个  if (entry == null) {  entry = virtualInvokers.firstEntry();  }  // 存在,则返回  return entry.getValue(); } 
 (编辑:源码网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |