前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Dubbo集群容错模式之Failback实现 原

Dubbo集群容错模式之Failback实现 原

作者头像
克虏伯
发布2019-04-15 14:47:17
5720
发布2019-04-15 14:47:17
举报

注: Dubbo版本是2.6.2

                                                 图1 Dubbo的FailbackClusterInvoker类继承图

1.Failback的含义

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

2.Failback的实现

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

代码语言:javascript
复制
@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)

代码语言:javascript
复制
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日志,不抛出异常,不中断后面的。

代码语言:javascript
复制
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进行重新调用。

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

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/05/18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Failback的含义
  • 2.Failback的实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档