dubbo源码分析第二十篇一dubbo集群容错策略-ForkingCluster并行调用

ForkingClusterInvoker

  • 并行调用forks数量的提供者【并非调用所有】
  • 谁先返回结果则先返回消费者
  • 支持timeout超时配置 通过阻塞队列的超时机制实现cluster集群层级超时
  • 同时底层请求层依旧采用timeout机制

public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    try {
        checkInvokers(invokers, invocation);
        final List<Invoker<T>> selected;
        最多并行调用Invoker数量 默认两个
        final int forks = getUrl().getParameter(FORKS_KEY, DEFAULT_FORKS);
        获取超时参数
        final int timeout = getUrl().getParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
        少于forks数量则全部调用
        if (forks <= 0 || forks >= invokers.size()) {
            selected = invokers;
        } else {
            否则选择forks数量的Invoker进行并行调用
            selected = new ArrayList<>(forks);
            while (selected.size() < forks) {
                Invoker<T> invoker = select(loadbalance, invocation, invokers, selected);
                if (!selected.contains(invoker)) {
                    //Avoid add the same invoker several times.
                    selected.add(invoker);
                }
            }
        }
        RpcContext.getContext().setInvokers((List) selected);
        final AtomicInteger count = new AtomicInteger();
        final BlockingQueue<Object> ref = new LinkedBlockingQueue<>();
        异步调用
        for (final Invoker<T> invoker : selected) {
            executor.execute(() -> {
                try {
                    Result result = invoker.invoke(invocation);
                    ref.offer(result);
                } catch (Throwable e) {
                    int value = count.incrementAndGet();
                    if (value >= selected.size()) {
                        ref.offer(e);
                    }
                }
            });
        }
        哪个先返回结果则通知消费者
        try {
            Object ret = ref.poll(timeout, TimeUnit.MILLISECONDS);
            if (ret instanceof Throwable) {
                Throwable e = (Throwable) ret;
                throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
            }
            return (Result) ret;
        } catch (InterruptedException e) {
            throw new RpcException("Failed to forking invoke provider " + selected + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e);
        }
    } finally {
        RpcContext.getContext().clearAttachments();
    }
}

你可能感兴趣的:(dubbo源码分析,负载均衡,rpc,dubbo)