美文网首页
Dubbo集群容错——Router

Dubbo集群容错——Router

作者: 就这些吗 | 来源:发表于2020-07-25 21:29 被阅读0次

本系列主要参考官网文档、芋道源码的源码解读和《深入理解Apache Dubbo与实战》一书。Dubbo版本为2.6.1。

文章内容顺序:
1.什么是Router?

  1. Router的UML图

3.Router是什么时候注入进来的?

  • 3.1 AbstractDirectory#setRouters
  • 3.2 RouterFactory
  • 3.3 ConditionRouterFactory
  • 3.4 FileRouterFactory
  1. Router接口
  • 4.1ConditionRouter
  • 4.2其他两个Router实现类

1.什么是Router?

在上一篇Dubbo集群容错——Directory中,可以看到在AbstractDirectory#list方法中,服务目录在获取可用 Invoker 列表后,会通过 Router 进行服务路由,筛选出符合路由规则的服务提供者。
服务路由包含一条路由规则,路由规则决定了服务消费者的调用目标,即规定了服务消费者可调用哪些服务提供者。
注:本文仅就简单分析下RouterFactory,对于Router的实现自认为写的没有官方详细(官方中只有ConditionRouter),对于Router实现部分请参考服务路由

2. Router的UML图

Router相关类如下图所示:


image.png

3.Router是什么时候注入进来的?

前文提到,在Directory篇中,服务目录在获取可用 Invoker 列表后,会通过 Router 进行服务路由,那么这个Router对象是怎么设置进来的呢?一起来看一下

3.1 AbstractDirectory#setRouters

image.png

可以看到在AbstractDirectory#setRouters就用SPI机制加载了routerFactory,调用了其getRouter,通过解析url来得到routers。接下里就来看看RouterFactory

3.2 RouterFactory

@SPI
public interface RouterFactory {

    /**
     * Create router.
     *
     * 创建 Router 对象
     *
     * @param url
     * @return router
     */
    @Adaptive("protocol")
    Router getRouter(URL url);

}

Dubbo SPI 拓展点,无默认值。接口方法用来获得 Router 对象。
来看看他的实现

3.3 ConditionRouterFactory

public class ConditionRouterFactory implements RouterFactory {

    public static final String NAME = "condition";

    @Override
    public Router getRouter(URL url) {
        return new ConditionRouter(url);
    }

}

对应 Router 实现类为 ConditionRouter 。

ScriptRouterFactory也是一样,直接返回了一个 new ScriptRouter(url),就不贴代码了。
FileRouterFactory有所不同。

3.4 FileRouterFactory

/**
 * 基于文件读取路由规则,创建对应的 Router 实现类的对象
 */
public class FileRouterFactory implements RouterFactory {

    public static final String NAME = "file";

    /**
     * RouterFactory$Adaptive 对象
     */
    private RouterFactory routerFactory;

    public void setRouterFactory(RouterFactory routerFactory) {
        this.routerFactory = routerFactory;
    }

    @Override
    public Router getRouter(URL url) {
        try {
            // Transform File URL into Script Route URL, and Load
            // file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule=<file-content>
            // 获得 router 配置项,默认为 script
            String protocol = url.getParameter(Constants.ROUTER_KEY, ScriptRouterFactory.NAME); // Replace original protocol (maybe 'file') with 'script'
            // 使用文件后缀做为类型
            String type = null; // Use file suffix to config script type, e.g., js, groovy ...
            String path = url.getPath();
            if (path != null) {
                int i = path.lastIndexOf('.');
                if (i > 0) {
                    type = path.substring(i + 1);
                }
            }
            // 读取规则内容
            String rule = IOUtils.read(new FileReader(new File(url.getAbsolutePath())));

            // 创建路由规则 URL
            boolean runtime = url.getParameter(Constants.RUNTIME_KEY, false);
            URL script = url.setProtocol(protocol).addParameter(Constants.TYPE_KEY, type)
                    .addParameter(Constants.RUNTIME_KEY, runtime)
                    .addParameterAndEncoded(Constants.RULE_KEY, rule);

            // 通过 Dubbo SPI Adaptive 机制,获得 Router 对象
            return routerFactory.getRouter(script);
        } catch (IOException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}

这个方法最后仍然是需要调用其他两个RouterFactory实现来读取文件,默认为ScriptRouterFactory。

4.Router接口

接下来看一下Router接口

public interface Router extends Comparable<Router> {

    /**
     * get the router url.
     * <p>
     * 路由规则 URL
     *
     * @return url
     */
    URL getUrl();

    /**
     * route.
     *
     * 路由,筛选匹配的 Invoker 集合
     *
     * @param invokers   Invoker 集合
     * @param url        refer url
     * @param invocation
     * @return routed invokers 路由后的 Invoker 集合
     * @throws RpcException
     */
    <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;

}

一个 Router 对象,对应一条路由规则。
注意,实现了Comparable接口,用于排序,路由规则优先级越大越靠前执行,可不填,缺省为 0

4.1 ConditionRouter

ConditionRouter的代码解读还是官方比较全面,还有详细的例子:服务路由

  • 这里总结一下ConditionRouter的代码逻辑:
    当创建ConditionRouter对象时,ConditionRouter 构造方法先是对路由规则做预处理,然后调用 parseRule方法分别对服务提供者和消费者规则进行解析。
    route 方法先是调用 matchWhen 对服务消费者进行匹配,如果匹配失败,直接返回 Invoker列表。如果匹配成功,再对服务提供者进行匹配,匹配逻辑封装在了 matchThen 方法中。matchWhenmatchThen 的区别仅在于,调用matchCondition时传的url不同。matchWhen对应服务提供者 urlmatchThen对应服务消费者 url

4.2其他两个Router实现类

对于ScriptRouter,与ConditionRouter的区别就是从配置文件读还是从脚本文件读。
MockInvokerSeclector我们留待到Mock的时候再来详细讲解。

相关文章

网友评论

      本文标题:Dubbo集群容错——Router

      本文链接:https://www.haomeiwen.com/subject/qbbfkktx.html