Dubbo集群容错模式之Failback实现

注: Dubbo版本是2.6.2java

              

                                                 图1 Dubbo的FailbackClusterInvoker类继承图ide

1.Failback的含义

    Failback能够理解为后台记录失败请求,定时重发。this

2.Failback的实现

    核心代码在FailbackClusterInvoker的doInvoke(Invocation,List<Invoker<T>>,LoadBalance)中,源码以下。spa

@Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    try {
        checkInvokers(invokers, invocation);
        Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
        return invoker.invoke(invocation);
    } catch (Throwable e) {
        logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
                + e.getMessage() + ", ", e);
        addFailed(invocation, this);
        return new RpcResult(); // ignore
    }
}
  • 首先根据loadbalance从服务提供者列表中取出一个服务提供者。
  • 调用服务提供者的服务,若是成功则直接返回调用结果;若是请求失败,用error日志记录,以后将这次请求的信息(参数、上下文)保存起来,用定时任务重发。

   

下面来分析addFailed方法的实现日志

    addFailed(invocation,this)的方法源码以下,将invocation和router放如到failed里面(failed是个ConcurrentHashMap)code

private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) {
    if (retryFuture == null) {
        synchronized (this) {
            if (retryFuture == null) {
                retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {

                    @Override
                    public void run() {
                        // collect retry statistics
                        try {
                            retryFailed();
                        } catch (Throwable t) { // Defensive fault tolerance
                            logger.error("Unexpected error occur at collect statistic", t);
                        }
                    }
                }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS);
            }
        }
    }
    failed.put(invocation, router);
}

    retryFailed()方法源码以下,遍历failed中的每一个,若是其中一个请求发生异常,则只是记录error日志,不抛出异常,不中断后面的。router

void retryFailed() {
    if (failed.size() == 0) {
        return;
    }
    for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>(
            failed).entrySet()) {
        Invocation invocation = entry.getKey();
        Invoker<?> invoker = entry.getValue();
        try {
            invoker.invoke(invocation);
            failed.remove(invocation);
        } catch (Throwable e) {
            logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e);
        }
    }
}

    

    假设定时任务10s中执行一次,0s时已经执行过一次。则若是0s到10s之间失败的请求的有A、B、C,则在10s这个时间点,就会开始对A、B、C进行从新调用。继承

    重点在于,对失败的请求,会记录下来,然后定时重发。rem

相关文章
相关标签/搜索