1. 程式人生 > >【Dubbo 源碼解析】07_Dubbo 重試機制

【Dubbo 源碼解析】07_Dubbo 重試機制

version ast 查看 error enabled pre div set time

Dubbo 重試機制

通過前面 Dubbo 服務發現&引用 的分析,我們知道,Dubbo 的重試機制是通過 com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker 來實現的:

public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    List<Invoker<T>> copyinvokers = invokers;
    checkInvokers(copyinvokers, invocation);
    
// 默認重試 2 次 int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1; if (len <= 0) { len = 1; } // retry loop. RpcException le = null; // last exception. List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); //
invoked invokers. Set<String> providers = new HashSet<String>(len); for (int i = 0; i < len; i++) { //Reselect before retry to avoid a change of candidate `invokers`. //NOTE: if `invokers` changed, then `invoked` also lose accuracy. if (i > 0) { checkWhetherDestroyed(); copyinvokers
= list(invocation); // check again checkInvokers(copyinvokers, invocation); } // 選擇重試的 Invoker Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked); invoked.add(invoker); RpcContext.getContext().setInvokers((List) invoked); try { Result result = invoker.invoke(invocation); if (le != null && logger.isWarnEnabled()) { logger.warn("Although retry the method " + invocation.getMethodName() + " in the service " + getInterface().getName() + " was successful by the provider " + invoker.getUrl().getAddress() + ", but there have been failed 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); } return result; } catch (RpcException e) { if (e.isBiz()) { // biz exception. throw e; } le = e; } catch (Throwable e) { le = new RpcException(e.getMessage(), e); } finally { providers.add(invoker.getUrl().getAddress()); } } throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method " + invocation.getMethodName() + " 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 != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le); }

查看源碼我們可以發現,dubbo 默認的重試次數是 2 次,也就是說,為了容錯性,如果第一次調用出異常(非業務異常)的話,Dubbo 會重試其他的 Invoker 2 次(具體的重試算法請查看源碼),如果還是失敗的話,就拋出 RpcException。所以默認情況下,服務最多被調用 3 次。

註意:

  1. 這裏的調用異常通常是指超時異常、網絡異常等,具體可以查看 RpcException#isBiz() 方法

  2. 重試算法會優先重試 stickyInvoker,沒有的話,會調用 LoadBalance 擴展來選擇 Invoker。(具體實現請查看源碼)

【Dubbo 源碼解析】07_Dubbo 重試機制