FailoverClusterInvoker总结
FailoverClusterInvoker重试会重新调用list(获取提供者集合外加路由)获取最新Invoker结果,因提供者可能有变动,重新获取本地缓存,确保监听变更后的RegisterDirectory能被及时感知重试通过循环实现
public Result doInvoke(Invocation invocation, final List总结> invokers, LoadBalance loadbalance) throws RpcException { List > copyInvokers = invokers; checkInvokers(copyInvokers, invocation); String methodName = RpcUtils.getMethodName(invocation); 获取重试次数加自身调用一次 int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; } // retry loop. RpcException le = null; // last exception. List > invoked = new ArrayList >(copyInvokers.size()); // invoked invokers. Set providers = new HashSet (len); 第一次加两次重试循环 for (int i = 0; i < len; i++) { if (i > 0) { checkWhetherDestroyed(); 在进行重试前重新列举 Invoker,这样做的好处是,如果某个服务挂了, 通过调用 list 可得到最新可用的 Invoker 列表原因是register是监听zk的 copyInvokers = list(invocation); check again checkInvokers(copyInvokers, invocation); } 通过负载均衡策略选择Invoker Invoker invoker = select(loadbalance, invocation, copyInvokers, invoked); invoked.add(invoker); RpcContext.getContext().setInvokers((List) invoked); try { Result result = invoker.invoke(invocation); return result; } catch (RpcException e) { if (e.isBiz()) { throw e; } le = e; } catch (Throwable e) { le = new RpcException(e.getMessage(), e); } finally { providers.add(invoker.getUrl().getAddress()); } } 重试都失败则抛出异常 throw new RpcException(le.getCode(), "Failed to invoke the method " + methodName + " in the service " + getInterface().getName() + ". Tried " + len + " times of the providers " + providers + " (" + providers.size() + "/" + copyInvokers.size() + ") from the registry " + directory.getUrl().getAddress() + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + Version.getVersion() + ". Last error is: " + le.getMessage(), le.getCause() != null ? le.getCause() : le); }
假设配置timeout1秒,加上重试3次,一个接口就会出现3秒超时注意此场景带来的雪崩效应



