dubbo源码分析第二十一篇一dubbo集群容错策略-ZoneAwareCluster区域调用

背景

服务部署亚洲区域和欧洲区域两个集群
自然希望亚洲区域消费者先调用亚洲区域集群,失败在调用欧洲区域集群

eureka中出现zone概念,类似dubbo这里的调度策略

ZoneAwareClusterInvoker

  • 存在首选的优先首选调用
  • 调用同区域
  • 无同区域且必须同区域调用则报错
  • 负载均衡一次选择一个可用
  • 所有提供者选择一个可用的
  • 强行调用


 public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        // registry.preferred = true 
    存在首选配置 则直接调用
    for (Invoker<T> invoker : invokers) {
        ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;
        if (clusterInvoker.isAvailable() && clusterInvoker.getRegistryUrl()
                .getParameter(REGISTRY_KEY + "." + PREFERRED_KEY, false)) {
            return clusterInvoker.invoke(invocation);
        }
    }

    获取当前所属区域 则直接调用同区域提供者
    String zone = invocation.getAttachment(REGISTRY_ZONE);
    if (StringUtils.isNotEmpty(zone)) {
        for (Invoker<T> invoker : invokers) {
            ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;
            if (clusterInvoker.isAvailable() && zone.equals(clusterInvoker.getRegistryUrl().getParameter(REGISTRY_KEY + "." + ZONE_KEY))) {
                return clusterInvoker.invoke(invocation);
            }
        }
        必须同区域调用 则直接报错
        String force = invocation.getAttachment(REGISTRY_ZONE_FORCE);
        if (StringUtils.isNotEmpty(force) && "true".equalsIgnoreCase(force)) {
            throw new IllegalStateException("No registry instance in zone or no available providers in the registry, zone: "
                    + zone
                    + ", registries: " + invokers.stream().map(invoker -> ((MockClusterInvoker<T>) invoker).getRegistryUrl().toString()).collect(Collectors.joining(",")));
        }
    }


    通过负载均选择调用
    Invoker<T> balancedInvoker = select(loadbalance, invocation, invokers, null);
    if (balancedInvoker.isAvailable()) {
        return balancedInvoker.invoke(invocation);
    }

    负载均选择isAvailable不可用,则兜底选择可用的调用
    for (Invoker<T> invoker : invokers) {
        ClusterInvoker<T> clusterInvoker = (ClusterInvoker<T>) invoker;
        if (clusterInvoker.isAvailable()) {
            return clusterInvoker.invoke(invocation);
        }
    }

     没有一个isAvailable可用,则兜底调用
    return invokers.get(0).invoke(invocation);
}

思考

一般zone,我们期望同区域调用失败,在调用其他区域

String zone = invocation.getAttachment(REGISTRY_ZONE);

zone可否改成zone1,zone2,zone3
当zone1失败,降级zone2,而不是直接调用整个集群所有的提供者中可用的

从而更好地支持灾备与双活架构?

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