Dubbo consumer和provider匹配逻辑分析

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 开篇 这篇文章用于分析Dubbo consumer匹配provider端URL的逻辑,一个简单的场景如在provider侧提供多版本的service的时候,consumer侧能够根据版本匹配到正确的接口并进行访问。

开篇

 这篇文章用于分析Dubbo consumer匹配provider端URL的逻辑,一个简单的场景如在provider侧提供多版本的service的时候,consumer侧能够根据版本匹配到正确的接口并进行访问。

 通过这篇后如果发现provider侧服务发布,但是consumer端没有发现服务,就应该考虑到provider和consumer侧的服务的不匹配。


consumer服务匹配逻辑分析

  • 获取path目录下所有服务提供者children ,List children = zkClient.addChildListener(path, zkListener)。
  • 针对所有的URL的集合children通过toUrlsWithEmpty(url, path, children)进行匹配逻辑判断。
public class ZookeeperRegistry extends FailbackRegistry {

    public void doSubscribe(final URL url, final NotifyListener listener) {
        try {
            if (ANY_VALUE.equals(url.getServiceInterface())) {
                   // 忽略这部分代码
            } else {
                List<URL> urls = new ArrayList<>();
                for (String path : toCategoriesPath(url)) {
                    ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
                    if (listeners == null) {
                        zkListeners.putIfAbsent(url, new ConcurrentHashMap<>());
                        listeners = zkListeners.get(url);
                    }
                    ChildListener zkListener = listeners.get(listener);
                    if (zkListener == null) {
                        listeners.putIfAbsent(listener, 
                        (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(
                               url, listener, toUrlsWithEmpty(url, parentPath, currentChilds)));
                        zkListener = listeners.get(listener);
                    }
                    zkClient.create(path, false);
                    // 获取providers、routes等目录的子节点
                    List<String> children = zkClient.addChildListener(path, zkListener);
                    if (children != null) {
                        // 添加符合条件的URL连接,通过toUrlsWithEmpty()内部进行判断
                        urls.addAll(toUrlsWithEmpty(url, path, children));
                    }
                }
                notify(url, listener, urls);
            }
        } catch (Throwable e) {
            
        }
    }
}


  • toUrlsWithEmpty()内部调用toUrlsWithoutEmpty()方法。
public class ZookeeperRegistry extends FailbackRegistry {

    private List<URL> toUrlsWithEmpty(URL consumer, String path, List<String> providers) {
        List<URL> urls = toUrlsWithoutEmpty(consumer, providers);
        if (urls == null || urls.isEmpty()) {
            int i = path.lastIndexOf(PATH_SEPARATOR);
            String category = i < 0 ? path : path.substring(i + 1);
            URL empty = URLBuilder.from(consumer)
                    .setProtocol(EMPTY_PROTOCOL)
                    .addParameter(CATEGORY_KEY, category)
                    .build();
            urls.add(empty);
        }
        return urls;
    }
}


  • 针对每个provider执行isMatch()的逻辑匹配。
  • 逻辑匹配逻辑在UrlUtils.isMatch()当中匹配。
public class ZookeeperRegistry extends FailbackRegistry {

    private List<URL> toUrlsWithoutEmpty(URL consumer, List<String> providers) {
        List<URL> urls = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(providers)) {
            for (String provider : providers) {
                // 针对每个provider执行isMatch()的逻辑匹配
                provider = URL.decode(provider);
                if (provider.contains(PROTOCOL_SEPARATOR)) {
                    URL url = URL.valueOf(provider);
                    if (UrlUtils.isMatch(consumer, url)) {
                        urls.add(url);
                    }
                }
            }
        }
        return urls;
    }
}


  • 核心的匹配逻辑在isMatch()方法当中。
  • 前置判断Interface是否相同。
  • 前置判断category是否相同。
  • 前置判断enabled是否为true。
  • 判断provider和consumer的Group+Version+Classifier三者是否相同,不相同就返回false。
public class UrlUtils {

    public static boolean isMatch(URL consumerUrl, URL providerUrl) {
        String consumerInterface = consumerUrl.getServiceInterface();
        String providerInterface = providerUrl.getServiceInterface();
        // 比较Interface的服务名是否相同,同时考虑了"*"这种逻辑。
        if (!(ANY_VALUE.equals(consumerInterface)
                || ANY_VALUE.equals(providerInterface)
                || StringUtils.isEquals(consumerInterface, providerInterface))) {
            return false;
        }
        // 比较category是否相同
        if (!isMatchCategory(providerUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY),
                consumerUrl.getParameter(CATEGORY_KEY, DEFAULT_CATEGORY))) {
            return false;
        }
        // 比较enabled是否相同
        if (!providerUrl.getParameter(ENABLED_KEY, true)
                && !ANY_VALUE.equals(consumerUrl.getParameter(ENABLED_KEY))) {
            return false;
        }
        // 比较consumerGroup、consumerVersion 、consumerClassifier 三者关系
        String consumerGroup = consumerUrl.getParameter(GROUP_KEY);
        String consumerVersion = consumerUrl.getParameter(VERSION_KEY);
        String consumerClassifier = consumerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);

        String providerGroup = providerUrl.getParameter(GROUP_KEY);
        String providerVersion = providerUrl.getParameter(VERSION_KEY);
        String providerClassifier = providerUrl.getParameter(CLASSIFIER_KEY, ANY_VALUE);
        // 只有Group+Version+Classifier三者相同的才相等。
        return (ANY_VALUE.equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) 
                     || StringUtils.isContains(consumerGroup, providerGroup))
                && (ANY_VALUE.equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion))
                && (consumerClassifier == null || ANY_VALUE.equals(consumerClassifier) 
                       || StringUtils.isEquals(consumerClassifier, providerClassifier));
    }
}


总结

  • consumer和provider在服务的核心匹配逻辑在于判断Group+Version+Classifier三者是否相同。
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
目录
相关文章
|
5月前
|
负载均衡 Dubbo 应用服务中间件
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
54 0
|
Dubbo Java 应用服务中间件
Dubbo-线程池调优实战分析
Dubbo-线程池调优实战分析
811 0
|
3月前
|
负载均衡 Dubbo 算法
深入理解Dubbo-2.Dubbo功能之高级特性分析
深入理解Dubbo-2.Dubbo功能之高级特性分析
56 0
|
21天前
|
Java fastjson 数据安全/隐私保护
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
38 0
|
4月前
|
Dubbo Java 应用服务中间件
Dubbo的原理分析
Dubbo的原理分析
39 0
|
7月前
|
存储 Dubbo Java
dubbo 源码 v2.7 分析:通信过程及序列化协议
前面我们介绍了dubbo的核心机制,今天将开始分析远程调用流程。毕竟,作为一个rpc框架,远程调用是理论的核心内容。通过对dubbo相关实现的探究,深入了解rpc原理及可能的问题。
125 0
|
7月前
|
负载均衡 Dubbo Java
dubbo源码v2.7分析:结构、container入口及线程模型
Apache Dubbo 是一款高性能、轻量级的开源 Java 服务框架,提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。
65 0
|
8月前
|
负载均衡 监控 Dubbo
Dubbo底层原理分析和分布式实际应用
Dubbo底层原理分析和分布式实际应用
|
8月前
|
Dubbo 应用服务中间件 Apache
集成Nacos1.2.1和Dubbo2.7.6 消费者报错No provider available for the service xxx
集成Nacos1.2.1和Dubbo2.7.6 消费者报错No provider available for the service xxx
84 0
|
11月前
|
安全 Dubbo 应用服务中间件
Dubbo反序列化漏洞复现分析(二)
Dubbo反序列化漏洞复现分析(二)

热门文章

最新文章