Dubbo集群容错模式之Failback实现

注: Dubbo版本是2.6.2

              

                                                 图1 Dubbo的FailbackClusterInvoker类继承图

1.Failback的含义

    Failback可以理解为后台记录失败请求,定时重发。

2.Failback的实现

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

@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)

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日志,不抛出异常,不中断后面的。

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进行重新调用。

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

转载于:https://my.oschina.net/u/2518341/blog/1814913

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值