精华内容
下载资源
问答
  • Ribbon fegin自定义路由规则,公司本地环境共用一个注册中心路由到本地服务,直接把该类放到项目中即可,不用任何配置
  • 主要介绍了详解Spring Cloud Gateway基于服务发现的默认路由规则,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 结合前面我们把路由规则写在项目的配置文件中.现在把结合SpringCloud-config 分布式配置中心,让配置文件更加的灵活。使用actuator 手动刷新,后面在说springcloud 消息总线 实现动态刷新配置。
  • 自定义路由规则示例

    2013-03-28 20:59:21
    对URL Routing进行演示描述
  • tp开启路由后,使用U方法是不会按路由规则生成url的,一般我们是要手动修改模版,把里面的U方法去掉,手动修改链接,如果是已经写好的程序,后期才添加路由,修改起链接就太麻烦了 今天无聊就修改了一下U方法,让它...
  • dubbo路由规则及源码分析

    千次阅读 2019-08-19 11:42:16
    路由规则 [1] 决定一次 dubbo 服务调用的目标服务器,分为条件路由规则和脚本路由规则,并且支持可扩展 [2]。 写入路由规则 向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成 RegistryFactory ...

    路由规则

    路由规则 [1] 决定一次 dubbo 服务调用的目标服务器,分为条件路由规则和脚本路由规则,并且支持可扩展 [2]

    写入路由规则

    向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成

    RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
    Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
    registry.register(URL.valueOf("route://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11")));
    

    其中:

    • route:// 表示路由规则的类型,支持条件路由规则和脚本路由规则,可扩展,必填
    • 0.0.0.0 表示对所有 IP 地址生效,如果只想对某个 IP 的生效,请填入具体 IP,必填
    • com.foo.BarService 表示只对指定服务生效,必填
    • group=foo 对指定服务的指定group生效,不填表示对未配置group的指定服务生效
    • version=1.0对指定服务的指定version生效,不填表示对未配置version的指定服务生效
    • category=routers 表示该数据为动态配置类型,必填
    • dynamic=false 表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填
    • enabled=true 覆盖规则是否生效,可不填,缺省生效。
    • force=false 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 false
    • runtime=false 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 true,需要注意设置会影响调用的性能,可不填,缺省为 false
    • priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 0
    • rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11") 表示路由规则的内容,必填

    条件路由规则

    基于条件表达式的路由规则,如:host = 10.20.153.10 => host = 10.20.153.11

    规则:

    • => 之前的为消费者匹配条件,所有参数和消费者的 URL 进行对比,当消费者满足匹配条件时,对该消费者执行后面的过滤规则。
    • => 之后为提供者地址列表的过滤条件,所有参数和提供者的 URL 进行对比,消费者最终只拿到过滤后的地址列表。
    • 如果匹配条件为空,表示对所有消费方应用,如:=> host != 10.20.153.11
    • 如果过滤条件为空,表示禁止访问,如:host = 10.20.153.10 =>

    表达式:

    参数支持:

    • 服务调用信息,如:method, argument 等,暂不支持参数路由
    • URL 本身的字段,如:protocol, host, port 等
    • 以及 URL 上的所有参数,如:application, organization 等

    条件支持:

    • 等号 = 表示"匹配",如:host = 10.20.153.10
    • 不等号 != 表示"不匹配",如:host != 10.20.153.10

    值支持:

    • 以逗号 , 分隔多个值,如:host != 10.20.153.10,10.20.153.11
    • 以星号 * 结尾,表示通配,如:host != 10.20.*
    • 以美元符 $ 开头,表示引用消费者参数,如:host = $host

    示例:

    1. 排除预发布机:

      => host != 172.22.3.91
      
    2. 白名单 [3]

      host != 10.20.153.10,10.20.153.11 =>
      
    3. 黑名单:

      host = 10.20.153.10,10.20.153.11 =>
      
    4. 服务寄宿在应用上,只暴露一部分的机器,防止整个集群挂掉:

      => host = 172.22.3.1*,172.22.3.2*
      
    5. 为重要应用提供额外的机器:

      application != kylin => host != 172.22.3.95,172.22.3.96
      
    6. 读写分离:

      method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96
      method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
      
    7. 前后台分离:

      application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93
      application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96
      
    8. 隔离不同机房网段:

      host != 172.22.3.* => host != 172.22.3.*
      
    9. 提供者与消费者部署在同集群内,本机只访问本机的服务:

      => host = $host
      

    用Filter实现黑白名单

    https://blog.csdn.net/o9109003234/article/details/83869760

    注:还有种方式实现黑白名单是在请求服务时把这边的路由规则加进去,比较蠢,不再赘述,也可参考dubbo开源源码的路由规则测试相关类中的模拟实现

    脚本路由规则

    脚本路由规则 [4] 支持 JDK 脚本引擎的所有脚本,比如:javascript, jruby, groovy 等,通过 type=javascript 参数设置脚本类型,缺省为 javascript。

    "script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("(function route(invokers) { ... } (invokers))")
    

    基于脚本引擎的路由规则,如:

    function route(invokers) {
        var result = new java.util.ArrayList(invokers.size());
        for (i = 0; i < invokers.size(); i ++) {
            if ("10.20.153.10".equals(invokers.get(i).getUrl().getHost())) {
                result.add(invokers.get(i));
            }
        }
        return result;
    } (invokers)); // 表示立即执行方法
    

    标签路由规则

    标签路由规则 [5] ,当应用选择装配标签路由(TagRouter)之后,一次 dubbo 调用能够根据请求携带的 tag 标签智能地选择对应 tag 的服务提供者进行调用。

    服务提供者

    1. 给应用装配标签路由器:
    @Bean
    public ApplicationConfig applicationConfig() {
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("provider-book");
        applicationConfig.setQosEnable(false);
        // instruct tag router
        Map<String,String> parameters = new HashMap<>();
        parameters.put(Constants.ROUTER_KEY, "tag");
        applicationConfig.setParameters(parameters);
        return applicationConfig;
    }
    
    1. 给应用设置具体的标签:
    @Bean
    public ProviderConfig providerConfig(){
    	ProviderConfig providerConfig = new ProviderConfig();
    	providerConfig.setTag("red");
    	return providerConfig;
    }
    

    应用未装配 tag 属性或服务提供者未设置 tag 属性,都将被认为是默认的应用,这些默认应用将会在调用无法匹配 provider 时当作降级方案。

    服务消费者

    RpcContext.getContext().setAttachment(Constants.REQUEST_TAG_KEY,"red");
    

    请求标签的作用域为每一次 invocation,使用 attachment 来传递请求标签,注意保存在 attachment 中的值将会在一次完整的远程调用中持续传递,得益于这样的特性,我们只需要在起始调用时,通过一行代码的设置,达到标签的持续传递。

    目前仅仅支持 hardcoding 的方式设置 requestTag。注意到 RpcContext 是线程绑定的,优雅的使用 TagRouter 特性,建议通过 servlet 过滤器(在 web 环境下),或者定制的 SPI 过滤器设置 requestTag。

    规则描述

    1. request.tag=red 时优先选择 tag=red 的 provider。若集群中不存在与请求标记对应的服务,可以降级请求 tag=null 的 provider,即默认 provider。

    2. request.tag=null 时,只会匹配 tag=null 的 provider。即使集群中存在可用的服务,若 tag 不匹配就无法调用,这与规则1不同,携带标签的请求可以降级访问到无标签的服务,但不携带标签/携带其他种类标签的请求永远无法访问到其他标签的服务。


    1. 2.2.0 以上版本支持 ↩︎

    2. 路由规则扩展点:路由扩展 ↩︎

    3. 注意:一个服务只能有一条白名单规则,否则两条规则交叉,就都被筛选掉了 ↩︎

    4. 注意:脚本没有沙箱约束,可执行任意代码,存在后门风险 ↩︎

    5. 该特性在 2.7.0 以上版本支持 ↩︎

    路由扩展

    扩展说明

    从多个服务提者方中选择一个进行调用。

    扩展接口

    • org.apache.dubbo.rpc.cluster.RouterFactory
    • org.apache.dubbo.rpc.cluster.Router

    已知扩展

    • org.apache.dubbo.rpc.cluster.router.ScriptRouterFactory
    • org.apache.dubbo.rpc.cluster.router.FileRouterFactory

    扩展示例

    Maven 项目结构:

    src
     |-main
        |-java
            |-com
                |-xxx
                    |-XxxRouterFactory.java (实现LoadBalance接口)
        |-resources
            |-META-INF
                |-dubbo
                    |-org.apache.dubbo.rpc.cluster.RouterFactory (纯文本文件,内容为:xxx=com.xxx.XxxRouterFactory)
    

    XxxRouterFactory.java:

    package com.xxx;
    import org.apache.dubbo.rpc.cluster.RouterFactory;
    import org.apache.dubbo.rpc.Invoker;
    import org.apache.dubbo.rpc.Invocation;
    import org.apache.dubbo.rpc.RpcException;
    public class XxxRouterFactory implements RouterFactory {
        public <T> List<Invoker<T>> select(List<Invoker<T>> invokers, Invocation invocation) throws RpcException {
            // ...
        }
    }
    

    META-INF/dubbo/org.apache.dubbo.rpc.cluster.RouterFactory:

    xxx=com.xxx.XxxRouterFactory
    

    1. 简介

    服务目录在刷新 Invoker 列表的过程中,会通过 Router 进行服务路由,筛选出符合路由规则的服务提供者。在详细分析服务路由的源码之前,先来介绍一下服务路由是什么。服务路由包含一条路由规则,路由规则决定了服务消费者的调用目标,即规定了服务消费者可调用哪些服务提供者。Dubbo 目前提供了三种服务路由实现,分别为条件路由 ConditionRouter、脚本路由 ScriptRouter 和标签路由 TagRouter。其中条件路由是我们最常使用的,标签路由是一个新的实现,暂时还未发布,该实现预计会在 2.7.x 版本中发布。本篇文章将分析条件路由相关源码,脚本路由和标签路由这里就不分析了。

    2. 源码分析

    条件路由规则由两个条件组成,分别用于对服务消费者和提供者进行匹配。比如有这样一条规则:

    host = 10.20.153.10 => host = 10.20.153.11

    该条规则表示 IP 为 10.20.153.10 的服务消费者只可调用 IP 为 10.20.153.11 机器上的服务,不可调用其他机器上的服务。条件路由规则的格式如下:

    [服务消费者匹配条件] => [服务提供者匹配条件]

    如果服务消费者匹配条件为空,表示不对服务消费者进行限制。如果服务提供者匹配条件为空,表示对某些服务消费者禁用服务。官方文档中对条件路由进行了比较详细的介绍,大家可以参考下,这里就不过多说明了。

    条件路由实现类 ConditionRouter 在进行工作前,需要先对用户配置的路由规则进行解析,得到一系列的条件。然后再根据这些条件对服务进行路由。本章将分两节进行说明,2.1节介绍表达式解析过程。2.2 节介绍服务路由的过程。下面,我们先从表达式解析过程看起。

    2.1 表达式解析

    条件路由规则是一条字符串,对于 Dubbo 来说,它并不能直接理解字符串的意思,需要将其解析成内部格式才行。条件表达式的解析过程始于 ConditionRouter 的构造方法,下面一起看一下:

    public ConditionRouter(URL url) {
        this.url = url;
        // 获取 priority 和 force 配置
        this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
        this.force = url.getParameter(Constants.FORCE_KEY, false);
        try {
            // 获取路由规则
            String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
            if (rule == null || rule.trim().length() == 0) {
                throw new IllegalArgumentException("Illegal route rule!");
            }
            rule = rule.replace("consumer.", "").replace("provider.", "");
            // 定位 => 分隔符
            int i = rule.indexOf("=>");
            // 分别获取服务消费者和提供者匹配规则
            String whenRule = i < 0 ? null : rule.substring(0, i).trim();
            String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
            // 解析服务消费者匹配规则
            Map<String, MatchPair> when = 
                StringUtils.isBlank(whenRule) || "true".equals(whenRule) 
                    ? new HashMap<String, MatchPair>() : parseRule(whenRule);
            // 解析服务提供者匹配规则
            Map<String, MatchPair> then = 
                StringUtils.isBlank(thenRule) || "false".equals(thenRule) 
                    ? null : parseRule(thenRule);
            // 将解析出的匹配规则分别赋值给 whenCondition 和 thenCondition 成员变量
            this.whenCondition = when;
            this.thenCondition = then;
        } catch (ParseException e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
    

    如上,ConditionRouter 构造方法先是对路由规则做预处理,然后调用 parseRule 方法分别对服务提供者和消费者规则进行解析,最后将解析结果赋值给 whenCondition 和 thenCondition 成员变量。ConditionRouter 构造方法不是很复杂,这里就不多说了。下面我们把重点放在 parseRule 方法上,在详细介绍这个方法之前,我们先来看一个内部类。

    private static final class MatchPair {
        final Set<String> matches = new HashSet<String>();
        final Set<String> mismatches = new HashSet<String>();
    }
    

    MatchPair 内部包含了两个 Set 类型的成员变量,分别用于存放匹配和不匹配的条件。这个类两个成员变量会在 parseRule 方法中被用到,下面来看一下。

    private static Map<String, MatchPair> parseRule(String rule)
            throws ParseException {
        // 定义条件映射集合
        Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
        if (StringUtils.isBlank(rule)) {
            return condition;
        }
        MatchPair pair = null;
        Set<String> values = null;
        // 通过正则表达式匹配路由规则,ROUTE_PATTERN = ([&!=,]*)\s*([^&!=,\s]+)
        // 这个表达式看起来不是很好理解,第一个括号内的表达式用于匹配"&", "!", "=" 和 "," 等符号。
        // 第二括号内的用于匹配英文字母,数字等字符。举个例子说明一下:
        //    host = 2.2.2.2 & host != 1.1.1.1 & method = hello
        // 匹配结果如下:
        //     括号一      括号二
        // 1.  null       host
        // 2.   =         2.2.2.2
        // 3.   &         host
        // 4.   !=        1.1.1.1 
        // 5.   &         method
        // 6.   =         hello
        final Matcher matcher = ROUTE_PATTERN.matcher(rule);
        while (matcher.find()) {
           	// 获取括号一内的匹配结果
            String separator = matcher.group(1);
            // 获取括号二内的匹配结果
            String content = matcher.group(2);
            // 分隔符为空,表示匹配的是表达式的开始部分
            if (separator == null || separator.length() == 0) {
                // 创建 MatchPair 对象
                pair = new MatchPair();
                // 存储 <匹配项, MatchPair> 键值对,比如 <host, MatchPair>
                condition.put(content, pair);  
            // 如果分隔符为 &,表明接下来也是一个条件
            else if ("&".equals(separator)) {
                // 尝试从 condition 获取 MatchPair
                if (condition.get(content) == null) {
                    // 未获取到 MatchPair,重新创建一个,并放入 condition 中
                    pair = new MatchPair();
                    condition.put(content, pair);
                } else {
                    pair = condition.get(content);
                }
            }
            // 分隔符为 =
            else if ("=".equals(separator)) {
                if (pair == null)
                    throw new ParseException("Illegal route rule ...");
                values = pair.matches;
                // 将 content 存入到 MatchPair 的 matches 集合中
                values.add(content);
            }   
            //  分隔符为 != 
            else if ("!=".equals(separator)) {
                if (pair == null)
                    throw new ParseException("Illegal route rule ...");
                values = pair.mismatches;
                // 将 content 存入到 MatchPair 的 mismatches 集合中
                values.add(content);
            }      
            // 分隔符为 ,
            else if (",".equals(separator)) {
                if (values == null || values.isEmpty())
                    throw new ParseException("Illegal route rule ...");
                // 将 content 存入到上一步获取到的 values 中,可能是 matches,也可能是 mismatches
                values.add(content);
            } else {
                throw new ParseException("Illegal route rule ...");
            }
        }
        return condition;
    }
    

    以上就是路由规则的解析逻辑,该逻辑由正则表达式和一个 while 循环以及数个条件分支组成。下面通过一个示例对解析逻辑进行演绎。示例为 host = 2.2.2.2 & host != 1.1.1.1 & method = hello。正则解析结果如下:

        括号一      括号二
    1.  null       host
    2.   =         2.2.2.2
    3.   &         host
    4.   !=        1.1.1.1
    5.   &         method
    6.   =         hello
    

    现在线程进入 while 循环:

    第一次循环:分隔符 separator = null,content = "host"。此时创建 MatchPair 对象,并存入到 condition 中,condition = {"host": MatchPair@123}

    第二次循环:分隔符 separator = "=",content = "2.2.2.2",pair = MatchPair@123。此时将 2.2.2.2 放入到 MatchPair@123 对象的 matches 集合中。

    第三次循环:分隔符 separator = "&",content = "host"。host 已存在于 condition 中,因此 pair = MatchPair@123。

    第四次循环:分隔符 separator = "!=",content = "1.1.1.1",pair = MatchPair@123。此时将 1.1.1.1 放入到 MatchPair@123 对象的 mismatches 集合中。

    第五次循环:分隔符 separator = "&",content = "method"。condition.get("method") = null,因此新建一个 MatchPair 对象,并放入到 condition 中。此时 condition = {"host": MatchPair@123, "method": MatchPair@ 456}

    第六次循环:分隔符 separator = "=",content = "2.2.2.2",pair = MatchPair@456。此时将 hello 放入到 MatchPair@456 对象的 matches 集合中。

    循环结束,此时 condition 的内容如下:

    {
        "host": {
            "matches": ["2.2.2.2"],
            "mismatches": ["1.1.1.1"]
        },
        "method": {
            "matches": ["hello"],
            "mismatches": []
        }
    }
    

    路由规则的解析过程稍微有点复杂,大家可通过 ConditionRouter 的测试类对该逻辑进行测试。并且找一个表达式,对照上面的代码走一遍,加深理解。

    2.2 服务路由

    服务路由的入口方法是 ConditionRouter 的 router 方法,该方法定义在 Router 接口中。实现代码如下:

    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        if (invokers == null || invokers.isEmpty()) {
            return invokers;
        }
        try {
            // 先对服务消费者条件进行匹配,如果匹配失败,表明服务消费者 url 不符合匹配规则,
            // 无需进行后续匹配,直接返回 Invoker 列表即可。比如下面的规则:
            //     host = 10.20.153.10 => host = 10.0.0.10
            // 这条路由规则希望 IP 为 10.20.153.10 的服务消费者调用 IP 为 10.0.0.10 机器上的服务。
            // 当消费者 ip 为 10.20.153.11 时,matchWhen 返回 false,表明当前这条路由规则不适用于
            // 当前的服务消费者,此时无需再进行后续匹配,直接返回即可。
            if (!matchWhen(url, invocation)) {
                return invokers;
            }
            List<Invoker<T>> result = new ArrayList<Invoker<T>>();
            // 服务提供者匹配条件未配置,表明对指定的服务消费者禁用服务,也就是服务消费者在黑名单中
            if (thenCondition == null) {
                logger.warn("The current consumer in the service blacklist...");
                return result;
            }
            // 这里可以简单的把 Invoker 理解为服务提供者,现在使用服务提供者匹配规则对 
            // Invoker 列表进行匹配
            for (Invoker<T> invoker : invokers) {
                // 若匹配成功,表明当前 Invoker 符合服务提供者匹配规则。
                // 此时将 Invoker 添加到 result 列表中
                if (matchThen(invoker.getUrl(), url)) {
                    result.add(invoker);
                }
            }        
            // 返回匹配结果,如果 result 为空列表,且 force = true,表示强制返回空列表,
            // 否则路由结果为空的路由规则将自动失效
            if (!result.isEmpty()) {
                return result;
            } else if (force) {
                logger.warn("The route result is empty and force execute ...");
                return result;
            }
        } catch (Throwable t) {
            logger.error("Failed to execute condition router rule: ...");
        }    
        // 原样返回,此时 force = false,表示该条路由规则失效
        return invokers;
    }
    

    router 方法先是调用 matchWhen 对服务消费者进行匹配,如果匹配失败,直接返回 Invoker 列表。如果匹配成功,再对服务提供者进行匹配,匹配逻辑封装在了 matchThen 方法中。下面来看一下这两个方法的逻辑:

    boolean matchWhen(URL url, Invocation invocation) {
        // 服务消费者条件为 null 或空,均返回 true,比如:
        //     => host != 172.22.3.91
        // 表示所有的服务消费者都不得调用 IP 为 172.22.3.91 的机器上的服务
        return whenCondition == null || whenCondition.isEmpty() 
            || matchCondition(whenCondition, url, null, invocation);  // 进行条件匹配
    }
    

    private boolean matchThen(URL url, URL param) {
    // 服务提供者条件为 null 或空,表示禁用服务
    return !(thenCondition == null || thenCondition.isEmpty())
    && matchCondition(thenCondition, url, param, null); // 进行条件匹配
    }

    这两个方法长的有点像,不过逻辑上还是有差别的,大家注意看。这两个方法均调用了 matchCondition 方法,但它们所传入的参数是不同的。这个需要特别注意一下,不然后面的逻辑不好弄懂。下面我们对这几个参数进行溯源。matchWhen 方法向 matchCondition 方法传入的参数为 [whenCondition, url, null, invocation],第一个参数 whenCondition 为服务消费者匹配条件,这个前面分析过。第二个参数 url 源自 route 方法的参数列表,该参数由外部类调用 route 方法时传入。比如:

    private List<Invoker<T>> route(List<Invoker<T>> invokers, String method) {
        Invocation invocation = new RpcInvocation(method, new Class<?>[0], new Object[0]);
        List<Router> routers = getRouters();
        if (routers != null) {
            for (Router router : routers) {
                if (router.getUrl() != null) {
                    // 注意第二个参数
                    invokers = router.route(invokers, getConsumerUrl(), invocation);
                }
            }
        }
        return invokers;
    }
    

    上面这段代码来自 RegistryDirectory,第二个参数表示的是服务消费者 url。matchCondition 的 invocation 参数也是从这里传入的。

    接下来再来看看 matchThen 向 matchCondition 方法传入的参数 [thenCondition, url, param, null]。第一个参数不用解释了。第二个和第三个参数来自 matchThen 方法的参数列表,这两个参数分别为服务提供者 url 和服务消费者 url。搞清楚这些参数来源后,接下来就可以分析 matchCondition 方法了。

    private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) {
        // 将服务提供者或消费者 url 转成 Map
        Map<String, String> sample = url.toMap();
        boolean result = false;
        // 遍历 condition 列表
        for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) {
            // 获取匹配项名称,比如 host、method 等
            String key = matchPair.getKey();
            String sampleValue;
            // 如果 invocation 不为空,且 key 为 mehtod(s),表示进行方法匹配
            if (invocation != null && (Constants.METHOD_KEY.equals(key) || Constants.METHODS_KEY.equals(key))) {
                // 从 invocation 获取被调用方法的名称
                sampleValue = invocation.getMethodName();
            } else {
                // 从服务提供者或消费者 url 中获取指定字段值,比如 host、application 等
                sampleValue = sample.get(key);
                if (sampleValue == null) {
                    // 尝试通过 default.xxx 获取相应的值
                    sampleValue = sample.get(Constants.DEFAULT_KEY_PREFIX + key);
                }
            }        
            // --------------------✨ 分割线 ✨-------------------- //     
            if (sampleValue != null) {
                // 调用 MatchPair 的 isMatch 方法进行匹配
                if (!matchPair.getValue().isMatch(sampleValue, param)) {
                    // 只要有一个规则匹配失败,立即返回 false 结束方法逻辑
                    return false;
                } else {
                    result = true;
                }
            } else {
                // sampleValue 为空,表明服务提供者或消费者 url 中不包含相关字段。此时如果 
                // MatchPair 的 matches 不为空,表示匹配失败,返回 false。比如我们有这样
                // 一条匹配条件 loadbalance = random,假设 url 中并不包含 loadbalance 参数,
                // 此时 sampleValue = null。既然路由规则里限制了 loadbalance 必须为 random,
                // 但 sampleValue = null,明显不符合规则,因此返回 false
                if (!matchPair.getValue().matches.isEmpty()) {
                    return false;
                } else {
                    result = true;
                }
            }
        }
        return result;
    }
    

    如上,matchCondition 方法看起来有点复杂,这里简单说明一下。分割线以上的代码实际上用于获取 sampleValue 的值,分割线以下才是进行条件匹配。条件匹配调用的逻辑封装在 isMatch 中,代码如下:

    private boolean isMatch(String value, URL param) {
        // 情况一:matches 非空,mismatches 为空
        if (!matches.isEmpty() && mismatches.isEmpty()) {
            // 遍历 matches 集合,检测入参 value 是否能被 matches 集合元素匹配到。
            // 举个例子,如果 value = 10.20.153.11,matches = [10.20.153.*],
            // 此时 isMatchGlobPattern 方法返回 true
            for (String match : matches) {
                if (UrlUtils.isMatchGlobPattern(match, value, param)) {
                    return true;
                }
            }      
            // 如果所有匹配项都无法匹配到入参,则返回 false
            return false;
        }
        // 情况二:matches 为空,mismatches 非空
        if (!mismatches.isEmpty() && matches.isEmpty()) {
            for (String mismatch : mismatches) {
                // 只要入参被 mismatches 集合中的任意一个元素匹配到,就返回 false
                if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
                    return false;
                }
            }
            // mismatches 集合中所有元素都无法匹配到入参,此时返回 true
            return true;
        }
        // 情况三:matches 非空,mismatches 非空
        if (!matches.isEmpty() && !mismatches.isEmpty()) {
            // matches 和 mismatches 均为非空,此时优先使用 mismatches 集合元素对入参进行匹配。
            // 只要 mismatches 集合中任意一个元素与入参匹配成功,就立即返回 false,结束方法逻辑
            for (String mismatch : mismatches) {
                if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
                    return false;
                }
            }
            // mismatches 集合元素无法匹配到入参,此时再使用 matches 继续匹配
            for (String match : matches) {
                // 只要 matches 集合中任意一个元素与入参匹配成功,就立即返回 true
                if (UrlUtils.isMatchGlobPattern(match, value, param)) {
                    return true;
                }
            }    
            // 全部失配,则返回 false
            return false;
        }
        // 情况四:matches 和 mismatches 均为空,此时返回 false
        return false;
    }
    

    isMatch 方法逻辑比较清晰,由三个条件分支组成,用于处理四种情况。这里对四种情况下的匹配逻辑进行简单的总结,如下:

    条件过程
    情况一matches 非空,mismatches 为空遍历 matches 集合元素,并与入参进行匹配。只要有一个元素成功匹配入参,即可返回 true。若全部失配,则返回 false。
    情况二matches 为空,mismatches 非空遍历 mismatches 集合元素,并与入参进行匹配。只要有一个元素成功匹配入参,立即 false。若全部失配,则返回 true。
    情况三matches 非空,mismatches 非空优先使用 mismatches 集合元素对入参进行匹配,只要任一元素与入参匹配成功,就立即返回 false,结束方法逻辑。否则再使用 matches 中的集合元素进行匹配,只要有任意一个元素匹配成功,即可返回 true。若全部失配,则返回 false
    情况四matches 为空,mismatches 为空直接返回 false

    isMatch 方法是通过 UrlUtils 的 isMatchGlobPattern 方法进行匹配,因此下面我们再来看看 isMatchGlobPattern 方法的逻辑。

    public static boolean isMatchGlobPattern(String pattern, String value, URL param) {
        if (param != null && pattern.startsWith("$")) {
            // 引用服务消费者参数,param 参数为服务消费者 url
            pattern = param.getRawParameter(pattern.substring(1));
        }
        // 调用重载方法继续比较
        return isMatchGlobPattern(pattern, value);
    }
    public static boolean isMatchGlobPattern(String pattern, String value) {
        // 对 * 通配符提供支持
        if ("*".equals(pattern))
            // 匹配规则为通配符 *,直接返回 true 即可
            return true;
        if ((pattern == null || pattern.length() == 0)
                && (value == null || value.length() == 0))
            // pattern 和 value 均为空,此时可认为两者相等,返回 true
            return true;
        if ((pattern == null || pattern.length() == 0)
                || (value == null || value.length() == 0))
            // pattern 和 value 其中有一个为空,表明两者不相等,返回 false
            return false;
    	 // 定位 * 通配符位置
        int i = pattern.lastIndexOf('*');
        if (i == -1) {
            // 匹配规则中不包含通配符,此时直接比较 value 和 pattern 是否相等即可,并返回比较结果
            return value.equals(pattern);
        }
        // 通配符 "*" 在匹配规则尾部,比如 10.0.21.*
        else if (i == pattern.length() - 1) {
            // 检测 value 是否以“不含通配符的匹配规则”开头,并返回结果。比如:
            // pattern = 10.0.21.*,value = 10.0.21.12,此时返回 true
            return value.startsWith(pattern.substring(0, i));
        }
        // 通配符 "*" 在匹配规则头部
        else if (i == 0) {
            // 检测 value 是否以“不含通配符的匹配规则”结尾,并返回结果
            return value.endsWith(pattern.substring(i + 1));
        }
        // 通配符 "*" 在匹配规则中间位置
        else {
            // 通过通配符将 pattern 分成两半,得到 prefix 和 suffix
            String prefix = pattern.substring(0, i);
            String suffix = pattern.substring(i + 1);
            // 检测 value 是否以 prefix 开头,且以 suffix 结尾,并返回结果
            return value.startsWith(prefix) && value.endsWith(suffix);
        }
    }
    

    以上就是 isMatchGlobPattern 两个重载方法的全部逻辑,这两个方法分别对普通的匹配过程,以及”引用消费者参数“和通配符匹配等特性提供了支持。这两个方法的逻辑不是很复杂,且代码中也进行了比较详细的注释,因此就不多说了。

    3. 总结

    本篇文章对条件路由的表达式解析和服务路由过程进行了较为细致的分析。总的来说,条件路由的代码还是有一些复杂的,需要静下心来看。在阅读条件路由代码的过程中,要多调试。 关于脚本路由规则代码写的比较简单,参考https://segmentfault.com/a/1190000018141200#articleHeader7 以及 https://github.com/CrazyHZM/dubbo/tree/analyze-2.6.x/dubbo-cluster/src/main/java/com/alibaba/dubbo/rpc/cluster/router 2.7.X后增加了标签路由机制,有兴趣可以研读相关源码。同事生产环境需注意dubbo版本问题。

    展开全文
  • mvc的路由规则

    千次阅读 2019-03-04 15:54:30
    ASP.NET引入了路由,以消除将每个URL映射到物理文件的需求。路由使我们能够定义映射到请求处理程序的URL模式。这个请求处理程序可以是一个...存储在RouteTable中的应用程序的所有已配置路由将由路由引擎用于为传...

    https://blog.csdn.net/u011966339/article/details/79387818

    ASP.NET引入了路由,以消除将每个URL映射到物理文件的需求。路由使我们能够定义映射到请求处理程序的URL模式。这个请求处理程序可以是一个文件或类。

    路由:

       路由定义了URL模式和处理程序信息。存储在RouteTable中的应用程序的所有已配置路由将由路由引擎用于为传入请求确定适当的处理程序类或文件。

    配置路由:

       每个MVC应用程序必须配置(注册)至少一个默认由MVC框架配置的路由。您可以在RouteConfig类中注册路由,该路由位于App_Start文件夹下的RouteConfig.cs中。下图说明了如何在RouteConfig类中配置路由。

    URL模式:

       URL模式仅在URL中的域名部分之后被考虑。例如,网址格式“{controller}/{action}/{id}”看起来像localhost:1234/{controller}/{action}/ {id}。“localhost:1234 /”之后的任何内容都将被视为控制器名称。同样,控制器名称之后的任何内容都将被视为操作名称,然后是id参数的值。

     

    多重路由

       使用MapRoute扩展方法配置自定义路由。在MapRoute中提供至少两个参数,路由名称和url模式。Defaults参数是可选的。你可以注册具有不同名称的多个自定义路由。考虑下面的例子,我们注册“学生”路由。

    示例:自定义路由

     

    [csharp] view plain copy

    1. <span style="font-family:KaiTi_GB2312;font-size:18px;">public class RouteConfig  
    2. {  
    3.     public static void RegisterRoutes(RouteCollection routes)  
    4.     {  
    5.         routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
    6.   
    7.         routes.MapRoute(  
    8.             name: "Student",  
    9.             url: "students/{id}",  
    10.             defaults: new { controller = "Student", action = "Index"}  
    11.         );  
    12.   
    13.         routes.MapRoute(  
    14.             name: "Default",  
    15.             url: "{controller}/{action}/{id}",  
    16.             defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }  
    17.         );  
    18.     }  
    19. }   
    20. </span>  

       如上面的代码所示,Student路由的URL模式是students/{id},它指定任何以domainName/students开头的URL都必须由StudentController处理。请注意,我们还没有在URL模式中指定{action},因为我们希望每个以student开头的URL都应该使用StudentController的Index操作。我们已经指定了默认的控制器和动作来处理从域名/学生开始的任何URL请求。
       MVC框架按顺序评估每个路由。它从第一个配置的路由开始,如果传入的url不符合路由的URL模式,那么它将评估第二个路由等等。在上面的例子中,路由引擎将首先评估students路由,如果传入的网址不是以/students开始,那么只有它将考虑作为默认路由的第二路由。

     

    路由约束:

       通过配置路由约束来限制参数的值。例如,以下路由对id参数应用限制,即id的值必须是数字。

     

    [html] view plain copy

    1. <span style="font-family:KaiTi_GB2312;font-size:18px;">routes.MapRoute(  
    2.         name: "Student",  
    3.         url: "student/{id}/{name}/{standardId}",  
    4.         defaults: new { controller = "Student", action = "Index", id = UrlParameter.Optional, name = UrlParameter.Optional, standardId = UrlParameter.Optional },  
    5.         constraints: new { id = @"\d+" }  
    6.     );</span>  

      如果你给id参数的非数字值,那么这个请求将被另一个路由处理,或者如果没有匹配的路由,则会抛出“The resource could not be found”错误。

     

    注册路由

       在配置RouteConfig类中的所有路由之后,需要将其注册到Global.asax的Application_Start()事件中。这样它就可以将所有的路由包含到RouteTable中。

     

    [csharp] view plain copy

    1. <span style="font-family:KaiTi_GB2312;font-size:18px;">public class MvcApplication : System.Web.HttpApplication  
    2.     {  
    3.         protected void Application_Start()  
    4.         {  
    5.               RouteConfig.RegisterRoutes(RouteTable.Routes);  
    6.         }  
    7.     }</span>  

    下面表示注册路由的过程

     

    小结

       要点:

    (1)路由在MVC框架中起着重要的作用。将URL映射到物理文件或类(MVC中的控制器类)。
    (2)路由包含URL模式和处理程序信息。网址格式在域名后面开始。
    (3)路由可以在RouteConfig类中配置。还可以配置多个自定义路由。
    (4)路由约束对参数的值应用限制。
    (5)路由必须在Global.ascx.cs文件的Application_Start事件中注册。

    https://blog.csdn.net/slowlifes/article/details/72461440

    1、规则名:Default

    2、URL分段:{controller}/{action}/{id},分别有三段,第一段对应controller参数,第段为action参数,第三段为id参数

    3、URL段的默认值:controller为Home,action为Index,id = UrlParameter.Optional表示该参数为可选的。

    之所以我们访问http://www.xx.com/ 这样的URL网址能正确返回,是因为我们设置了URL段的默认值,相当于访问:

    http://www.xx.com/Home/Index

    1、Controller命名约定

    Controller类必须以Controller结尾,比如:HomeController,ProductController。我们在页面上用HTML heper来引用一个Controller的时只需要前面Home,Product就可以,ASP.NET MVC框架自带的DefaultControllerFactory自动为我们在结尾加上Controller,并开始根据这个名字开始找对应的类。我们创建一个ASP.NET MVC项目新加的Controller,文件会自动放在根目录的Controllers文件夹里面,我们刚开始可以看到有一个HomeController.cs。当然你也可以实现接口IControllerFactory,定义自己的ControllerFactory来改变查找Controller文件的行为。我会再以后的文章中介绍。

    2、View命名约定

    ASP.NET MVC的视图View默认情况是放在根目录的Views文件下的,规则是这样的:/Views/ControllerName/ActionName.cshtml。比如:HomeController的Action名字为Index的视图对应文件为:/Views/Home/Index.cshtml

    因此是通过Controller和Action的名字来确定视图文件的位置的。采用这个命名约定的好处是在Action返回视图的时候会MVC框架会按照这个约定找到默认的视图文件。比如在ProductController的Action方法List最后是这样的代码:

    return View();

    会自动去路径,/Views/Product/找文件List.cshtml(或者List.aspx如果使用的老的视图引擎)。

    当然也可以指定视图的名字:

    return View("~/Views/Product/List.cshtml")

    或者

    return View("MyOtherView")

     

    MVC框架在查找具体的默认视图文件时,如果在/Views/ControllerName/下面没有找到,会再在/Views/Shared下面找,如果都没找到就会找错:找不到视图。

    上面表示URL规则是:

    {controller}/{action} 

    这个路由规则有两个段,第一个是controller,第二个是action。声明url段每个部分要且{}括起来,相当于占位符,是变量。

    当一个URL请求到来的时候MVC路由系统就负责把它匹配到一个具体的路由规则,并把URL每段的值提取出来。这里说“一个具体的路由规则”,是因为可能会注册多个路由规则,MVC路由系统会根据注册顺序一个一个的查找匹配,直到到为止。

    默认情况,URL路由规则只匹配与之有相同URL段数量的URL。如下表:

    URL

    URL段

    http://mysite.com/Admin/Index

    controller = Admin

    action = Index 

    http://mysite.com/Index/Admin

    controller = Index

    action = Admin 

    http://mysite.com/Apples/Oranges

    controller = Apples

    action = Oranges

    http://mysite.com/Admin

    无匹配-段的数量不够

    http://mysite.com/Admin/Index/Soccer

    无匹配-段的数量超了

     

    四、mvc创建一个简单的Route规则

    我们在前面注册路由规则都是通过下面的方式:

    1 public static void RegisterRoutes(RouteCollection routes) {
    2  
    3     routes.MapRoute("MyRoute", "{controller}/{action}");
    4 }

    用到了RouteCollection的MapRoute方法。其实我们还可以调用 Add方法,传一个Route的实例给它一样的达到相同的效果。

    1 public static void RegisterRoutes(RouteCollection routes) {
    2  
    3     Route myRoute = new Route("{controller}/{action}", new MvcRouteHandler());
    4     routes.Add("MyRoute", myRoute);
    5 }

    五、mvc路由的默认值的设定

    之前有说:URL路由规则只匹配与之有相同URL段数量的URL,这种是严格,但是我们又想有些段不用输入,让用户进入指定的页面。像,http://www.xx.com/Home/就是进入进入Home的Index。只需要设定mvc路由的默认值就可以了。

    1 public static void RegisterRoutes(RouteCollection routes) {
    2     routes.MapRoute("MyRoute", "{controller}/{action}", new { action = "Index" });  
    3 }

    要设置Controller和Action的默认值。

    1 public static void RegisterRoutes(RouteCollection routes) {
    2  
    3 routes.MapRoute("MyRoute", "{controller}/{action}",
    4         new { controller = "Home", action = "Index" });
    5 } 

    下面是一个具体的Url对应的Route映射。

    Url段的数量

    实例

    Route映射

    0

    mydomain.com 

    controller = Home

    action = Index 

    1

    mydomain.com/Customer

    controller = Customer

    action = Index 

    2

    mydomain.com/Customer/List

    controller = Customer

    action = List 

    3

    mydomain.com/Customer/List/All

    无匹配—Url段过多 

     

    六、mvc使用静态URL段

    前面定义路由规则都是占位符的形式,{controller}/{action},我们也可以使用在使用静态字符串。如:

    复制代码

    1 public static void RegisterRoutes(RouteCollection routes) {
    2  
    3     routes.MapRoute("MyRoute", "{controller}/{action}",
    4         new { controller = "Home", action = "Index" });
    5  
    6     routes.MapRoute("", "Public/{controller}/{action}",
    7        new { controller = "Home", action = "Index" });
    8 }

    复制代码

    上面匹配:http://mydomain.com/Public/Home/Index

    路由:"Public/{controller}/{action}"只匹配有三段的url,第一段必须为Public,第二和第三可以是任何值,分别用于controller和action。

    除此这外,路由规则中可以既包含静态和变量的混合URL段,如:

    复制代码

     1 public static void RegisterRoutes(RouteCollection routes) {
     2  
     3     routes.MapRoute("", "X{controller}/{action}");
     4  
     5     routes.MapRoute("MyRoute", "{controller}/{action}",
     6         new { controller = "Home", action = "Index" });
     7  
     8     routes.MapRoute("", "Public/{controller}/{action}",
     9        new { controller = "Home", action = "Index" });
    10  
    11 } 
    展开全文
  • Re: 配置 ProxySQL 路由规则,实现 MySQL 读写分离和高可用 ================================== ProxySQL软件可以推荐在生产环境,成为MySQL中间件。虽然是一个轻量级产品,但性能很好(据测试,能处理千亿级pv的...
  • Dubbo-服务调用路由规则

    千次阅读 2019-01-20 11:26:38
    dubbo-服务调用路由规则 路由规则决定一次 dubbo 服务调用的目标服务器,分为条件路由规则和脚本路由规则,并且支持可扩展 。 写入路由规则 向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成 ...

    Dubbo-服务调用路由规则

    路由规则决定一次 dubbo 服务调用的目标服务器,分为条件路由规则和脚本路由规则,并且支持可扩展 。

    写入路由规则

    向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成

    RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
    Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
    registry.register(URL.valueOf("condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11")));
    

    其中:

    • condition:// 表示路由规则的类型,支持条件路由规则和脚本路由规则,可扩展,必填。
    • 0.0.0.0 表示对所有 IP 地址生效,如果只想对某个 IP 的生效,请填入具体 IP,必填。
    • com.foo.BarService 表示只对指定服务生效,必填。
    • group=foo 对指定服务的指定group生效,不填表示对未配置group的指定服务生效
    • version=1.0对指定服务的指定version生效,不填表示对未配置version的指定服务生效
    • category=routers 表示该数据为动态配置类型,必填。
    • dynamic=false 表示该数据为持久数据,当注册方退出时,数据依然保存在注册中心,必填。
    • enabled=true 覆盖规则是否生效,可不填,缺省生效。
    • force=false 当路由结果为空时,是否强制执行,如果不强制执行,路由结果为空的路由规则将自动失效,可不填,缺省为 false。
    • runtime=false 是否在每次调用时执行路由规则,否则只在提供者地址列表变更时预先执行并缓存结果,调用时直接从缓存中获取路由结果。如果用了参数路由,必须设为 true,需要注意设置会影响调用的性能,可不填,缺省为 false。
    • priority=1 路由规则的优先级,用于排序,优先级越大越靠前执行,可不填,缺省为 0。
    • rule=URL.encode(“host = 10.20.153.10 => host = 10.20.153.11”) 表示路由规则的内容,必填。

    条件路由规则

    基于条件表达式的路由规则,如:host = 10.20.153.10 => host = 10.20.153.11

    规则:

    • => 之前的为消费者匹配条件,所有参数和消费者的 URL 进行对比,当消费者满足匹配条件时,对该消费者执行后面的过滤规则。
    • => 之后为提供者地址列表的过滤条件,所有参数和提供者的 URL 进行对比,消费者最终只拿到过滤后的地址列表。
    • 如果匹配条件为空,表示对所有消费方应用,如:=> host != 10.20.153.11
    • 如果过滤条件为空,表示禁止访问,如:host = 10.20.153.10 =>

    表达式:

    参数支持:

    • 服务调用信息,如:method, argument 等,暂不支持参数路由
    • URL 本身的字段,如:protocol, host, port 等
    • 以及 URL 上的所有参数,如:application, organization 等

    条件支持:

    • 等号 = 表示"匹配",如:host = 10.20.153.10
    • 不等号 != 表示"不匹配",如:host != 10.20.153.10

    值支持:

    • 以逗号 , 分隔多个值,如:host != 10.20.153.10,10.20.153.11
    • 以星号 * 结尾,表示通配,如:host != 10.20.*
    • 以美元符 $ 开头,表示引用消费者参数,如:host = $host

    示例:

    1. 排除预发布机:
      => host != 172.22.3.91
    2. 白名单 [3]:
      host != 10.20.153.10,10.20.153.11 =>
    3. 黑名单:
      host = 10.20.153.10,10.20.153.11 =>
    4. 服务寄宿在应用上,只暴露一部分的机器,防止整个集群挂掉:
      => host = 172.22.3.1*,172.22.3.2*
    5. 为重要应用提供额外的机器:
      application != kylin => host != 172.22.3.95,172.22.3.96
    6. 读写分离:
      method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96
      method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
    7. 前后台分离:
      application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93
      application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96
    8. 隔离不同机房网段:
      host != 172.22.3.* => host != 172.22.3.*
    9. 提供者与消费者部署在同集群内,本机只访问本机的服务:
      => host = $host

    脚本路由规则

    脚本路由规则 [4] 支持 JDK 脚本引擎的所有脚本,比如:javascript, jruby, groovy 等,通过 type=javascript 参数设置脚本类型,缺省为 javascript。

    "script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("(function route(invokers) { ... } (invokers))")
    

    基于脚本引擎的路由规则,如:

    (function route(invokers) {
        var result = new java.util.ArrayList(invokers.size());
        for (i = 0; i < invokers.size(); i ++) {
            if ("10.20.153.10".equals(invokers.get(i).getUrl().getHost())) {
                result.add(invokers.get(i));
            }
        }
        return result;
    } (invokers)); // 表示立即执行方法
    

    标签路由规则

    标签路由规则 ,当应用选择装配标签路由(TagRouter)之后,一次 dubbo 调用能够根据请求携带的 tag 标签智能地选择对应 tag 的服务提供者进行调用。

    服务提供者

    1. 给应用装配标签路由器:

      @Bean
      public ApplicationConfig applicationConfig() {
      ApplicationConfig applicationConfig = new ApplicationConfig();
      applicationConfig.setName(“provider-book”);
      applicationConfig.setQosEnable(false);
      // instruct tag router
      Map<String,String> parameters = new HashMap<>();
      parameters.put(Constants.ROUTER_KEY, “tag”);
      applicationConfig.setParameters(parameters);
      return applicationConfig;
      }

    2. 给应用设置具体的标签:

      @Bean
      public ProviderConfig providerConfig(){
      ProviderConfig providerConfig = new ProviderConfig();
      providerConfig.setTag(“red”);
      return providerConfig;
      }

    应用未装配 tag 属性或服务提供者未设置 tag 属性,都将被认为是默认的应用,这些默认应用将会在调用无法匹配 provider 时当作降级方案。

    服务消费者

    RpcContext.getContext().setAttachment(Constants.REQUEST_TAG_KEY,"red");
    

    请求标签的作用域为每一次 invocation,使用 attachment 来传递请求标签,注意保存在 attachment 中的值将会在一次完整的远程调用中持续传递,得益于这样的特性,我们只需要在起始调用时,通过一行代码的设置,达到标签的持续传递。

    目前仅仅支持 hardcoding 的方式设置 requestTag。注意到 RpcContext 是线程绑定的,优雅的使用 TagRouter 特性,建议通过 servlet 过滤器(在 web 环境下),或者定制的 SPI 过滤器设置 requestTag。

    规则描述

    1. request.tag=red 时优先选择 tag=red 的 provider。若集群中不存在与请求标记对应的服务,可以降级请求 tag=null 的 provider,即默认 provider。
    2. request.tag=null 时,只会匹配 tag=null 的 provider。即使集群中存在可用的服务,若 tag 不匹配就无法调用,这与规则1不同,携带标签的请求可以降级访问到无标签的服务,但不携带标签/携带其他种类标签的请求永远无法访问到其他标签的服务。
    展开全文
  • 路由表,路由,路由规则 路由介绍 (Introduction to Routing ) The process of sending packets from one network to another is called routing. Routing is of two types of static and dynamic. Routes are based ...

    路由表,路由,路由规则

    路由介绍 (Introduction to Routing )

    The process of sending packets from one network to another is called routing. Routing is of two types of static and dynamic. Routes are based on the destination network. Routing is to find the best path for the network from one network to another. The best path is chosen on the basis of metric and administrative distance. Routing is performed by routers. For this routers make routing tables. Now let's understand about routing tables.

    从一个网络向另一个网络发送数据包的过程称为路由。 路由有静态和动态两种。 路由基于目标网络。 路由是为了找到从一个网络到另一个网络的最佳路径。 最佳路径是根据度量标准和管理距离来选择的。 路由由路由器执行。 为此路由器制作路由表。 现在让我们了解路由表。

    Routers make routing tables that contain the following information's:

    路由器制作的路由表包含以下信息:

    • Destination network and its subnet mask.

      目标网络及其子网掩码。

    • There is information about the next hop router to go to Destination network.

      有关于下一跳路由器去目的地网络的信息。

    • Routing metrics and administrative distance are stored.

      存储路由度量和管理距离。

    Routing tables are related to 2 types of protocols:

    路由表与两种协议类型有关:

    1. Routed protocols

      路由协议

      These are network layer protocols. Routed protocols attach to logical addresses with devices. These protocols are responsible for sending data from one network to another. For example, IP (Internet Protocol) and IPX etc.

      这些是网络层协议。 路由协议附加到设备的逻辑地址。 这些协议负责将数据从一个网络发送到另一个网络。 例如,IP(Internet协议)和IPX等。

    2. Routing protocols

      路由协议

      These protocols build networks, topology and next hop information in routing tables. All these information is created dynamically (automatic). For example, RIP, IGRP, and OSPF etc. Routing protocols are of 2 types.

      这些协议在路由表中构建网络,拓扑和下一跳信息。 所有这些信息都是动态(自动)创建的。 例如,RIP,IGRP和OSPF等。路由协议有2种类型。

      1. Distance vector距离矢量
      2. Link state链接状态

    To determine the best route to Destination network, the router uses the following 3 elements:

    为了确定到达目标网络的最佳路由,路由器使用以下3个元素:

    1. Prefix-Length

      前缀长度

      This is the number of bits to identify the network. From this, the most accurate route is determined. The longer the prefix length, the more precise the path is. For example, suppose a packet is going to 10.1.5.0/24 host and the router's routing table has 2 networks given.

      这是识别网络的位数。 由此确定最准确的路线。 前缀长度越长,路径越精确。 例如,假设有一个数据包到达10.1.5.0/24主机,并且路由器的路由表中有2个网络。

      10.1.5.0/24

      10.1.5.0/24

      10.0.0.0/8

      10.0.0.0/8

      So the first network will be selected on this because its prefix length is high. It does not matter what the metric or administrative distance is.

      因此将选择第一个网络,因为其前缀长度很高。 度量或管理距离是多少都没有关系。

    2. Metric

      公制

      The metric router gives the ability to find the best routes under the routing protocol. Distance vector uses the protocols distance as metric and link state protocols use the shortest path first algorithm as the metric used to calculate. The routes which are best metric are added to the routing tables. Even if a routing protocol has 4 routes to go to the same network, even if the metric is the best, it will only be added to the routing table. If more than one route of equal metric is available then correct metric will be selected by loading balance.

      公制路由器可以根据路由协议找到最佳路由。 距离向量使用协议距离作为度量标准,而链接状态协议使用最短路径优先算法作为用于计算的度量标准。 最佳度量标准的路由将添加到路由表中。 即使路由协议有4条路由到达同一网络,即使该度量标准是最佳的,也只会将其添加到路由表中。 如果有多条相等度量标准的路由可用,则将通过负载平衡选择正确的度量标准。

    3. Administrative Distance

      行政距离

      If more than one routing protocol is running on the router, then which protocol is to trust most, it is determined by the administrative distance. The administrative distance at the bottom is the lowest, the same protocol is chosen. Administrative distance is a numerical value that is assigned to dynamic protocols. It is fixed. The protocol whose administrative distance is unknown is never taken in the routing table.

      如果路由器上正在运行多个路由协议,那么哪个协议最受信任,取决于管理距离。 底部的管理距离是最低的,选择了相同的协议。 管理距离是分配给动态协议的数值。 它是固定的。 管理距离未知的协议永远不会在路由表中使用。

    查看路由表 (Viewing Routing Table )

    The routing table can be viewed on any router. For this, you need to run show IP route command. You can see it from the user execution mode.

    路由表可以在任何路由器上查看。 为此,您需要运行show IP route命令。 您可以从用户执行模式中看到它。

    #Router1 show ip route

    #Router1显示IP路由

    When you execute this command, the list of all routers is displayed to you. A label along with all these routers is also shown which is how it is connected to all the current router. The list of all these labels is being given below.

    当您执行此命令时,将显示所有路由器的列表。 还显示了带有所有这些路由器的标签,这是标签与所有当前路由器的连接方式。 所有这些标签的列表如下。

    • C - This label means that the given router is directly connected to the current router.

      C-此标签表示给定的路由器直接连接到当前路由器。

    • S - This label indicates that the given router has been statically managed.

      S-此标签表示给定的路由器已经过静态管理。

    • S * - This is the default route between the router given by the current router.

      S * -这是当前路由器给定的路由器之间的默认路由。

    • D - This label means that the given router is using the EIGRP protocol.

      D-此标签表示给定的路由器正在使用EIGRP协议。

    • I - This label states that given the router IGRP protocol is being used.

      I-此标签指出使用给定的路由器IGRP协议。

    • R - It says that the given router is using RIP protocol.

      R-表示给定的路由器正在使用RIP协议。

    • O - this label means that the given router is using OSPF protocol.

      O-此标签表示给定的路由器正在使用OSPF协议。

    Clearing Routing Table

    清除路由表

    If you want to clear all routes from the routing table, you can use the clear command for this. By clearing the Routing table, you can force routing protocols to populate the routing table again.

    如果要清除路由表中的所有路由,可以使用clear命令。 通过清除路由表,可以强制路由协议再次填充路由表。

    #Router clear ip route

    #router清除ip路由

    Choosing Best Route

    选择最佳路线

    You can follow the procedure given below to choose the best route to any destination router.

    您可以按照以下步骤选择到任何目标路由器的最佳路由。

    • First of all you will have to match the prefix length of the route with the destination route. You will choose the routes that are most accurate in the prefix length.

      首先,您必须将路由的前缀长度与目标路由匹配。 您将选择前缀长度中最准确的路由。

    • Now you have to choose the route from which route is the lowest metric.

      现在,您必须选择从哪个路由成为最低度量标准的路由。

    • If the same metric has more than one route then you will choose the route with the lowest administrative distance and this will be your best route.

      如果同一度量标准具有多条路线,则您将选择管理距离最小的路线,这将是您的最佳路线。

    翻译自: https://www.includehelp.com/computer-networks/introduction-to-routing-and-viewing-routing-table.aspx

    路由表,路由,路由规则

    展开全文
  • 主要介绍了thinkphp的URL路由规则与配置方法,实例分析了ThinkPHP的路由规则及伪静态设置方法,并分析了相关的注意事项,是ThinkPHP开发中非常重要的技巧,需要的朋友可以参考下
  • SpringCloud Gateway之路由规则

    千次阅读 2020-01-08 20:38:53
    我们把上面路由规则中的 After 改为 Before,则会在某个时间之前的请求都进行转发,如下: server : port : 8080 spring : application : name : test - GATEWAY cloud : gateway : routes :...
  • vue-router路由规则

    千次阅读 2019-10-29 18:25:11
    缺点是使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存 使用一个路由基本有6个步骤 1 引入对象 2 安装插件 3 创建路由对象 4 配置路由规则 5 把路由对象交给vue实例和留坑 Vue.use(VueRouter);...
  • 通过nacos动态配置springCloud gateway的路由规则 现状 目前对gateway的routes的配置有两种方式,一种是在代码里面配置,一重是在配置文件里配置。这两种配置方式配置后都需要重启网关才能生效。对于请求量很大的...
  • tp5.0路由规则

    千次阅读 2018-10-08 14:36:42
    默认的url规则是域名、模块、控制器、方法,参数,数值 路由的作用简化url访问地址,定义的路由类型做出正确的解析 若果一些木块需要关闭路由,需要给该模块增加单独的入口文件 //定义项目路径 define(‘APP_...
  • Express新建工程以及新建路由规则、匹配路由规则、控制权转移示例代码;Express新建工程以及新建路由规则、匹配路由规则、控制权转移示例代码
  • dubbo的路由规则

    千次阅读 2019-01-22 23:30:55
    使用了dubbo的keeper项目作为后台管理来新增路由规则,翻看dubbo源码,   发现dubbo使用了代理,代理会做的一件事就是使用路由规则, //AbstractDirectory 类 public List&lt;Invoker&lt;T&gt;&...
  • thinkphp 5.1 路由规则

    千次阅读 2018-09-29 19:10:56
    'default_route_pattern' =&gt; '[\w\-]+', 支持在规则路由中为变量用正则的方式指定变量规则,弥补了动态变量无法限制具体的类型问题,并且支持全局规则设置。...// 定义GET请求路由规则 并设置name变量规...
  • Vue router 3.x 实现路由规则增删

    千次阅读 2021-01-15 17:16:37
    vue 项目的权限限制功能, 有一种实现方案是这样的 进入项目 只设置没有权限要求的路由 ...怎么添加路由规则 怎么删除路由规则 路由规则 首先明确一下什么叫路由规则? 下例的 { path: ‘/foo’, component: F
  • NLog配置路由规则和上下文信息 rules: 规则节点 logger:一个路由规则 <!--* writeTo=console>--> * minlevel=Debug writeTo=debugger> * minlevel=Error writeTo=error_file> 具体参数说明: 路由...
  • (六)路由规则

    千次阅读 2017-05-06 19:24:27
    路由规则 功能配置 路由功能,就是 消费者 -&gt; 提供者 即是根据配置的路由规则,找到提供者, 比如,读写分离 路由规则: 读路由: method = find*,list*,get*,is* =&gt; host = 172.22.3.94,172.22....
  • 通过角色身份删除对应的路由规则使用场景实现思路将全局路由整合通过react-redux实现全局修改路由渲染组件最后一步大功告成重置路由规则写在最后 使用场景 我们一般在做类似于后台管理系统时,一般都会有两个甚至多...
  • Ubuntu添加路由规则

    千次阅读 2019-10-14 23:24:39
    因为Ubuntu默认使用NetworkManager进行网络管理,所以修改interfaces配置文件是与NetworkManager相悖的,所以使用nmcli这个NetworkManager命令行工具,或者图形界面添加路由规则是比较优雅的。 route 命令 sudo ...
  • Zuul默认路由规则

    千次阅读 2020-03-25 12:27:07
  • Spring Cloud Gateway路由规则

    千次阅读 2020-11-06 10:47:26
    Route(路由):路由是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发 Predicate(谓语、断言):路由转发的判断条件,目前SpringCloud Gateway支持多种方式,常见如:Path...
  • ThinkPHP路由规则

    千次阅读 2018-04-02 16:47:38
    版本说明:VERSION = 5.1.7;方法定义路由规则定义2种访问方式对于Route::rule('new/:id','News/read');的2种请求方式
  • ThinkPHP5.0教程学习04:TP5框架的URL路由规则与配置技巧
  • 网关gateway之常见路由规则有哪些? 完成:第一遍 1.网关gateway之常见路由规则有哪些? 在application.yml中配置路由规则 server: port: 9001 spring: application: name: gateway cloud: gateway: routes: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 190,186
精华内容 76,074
关键字:

路由规则