Dubbo路由规则:静态标签的使用与扩展

2023-11-01

一、路由的流程

路由是通过互联网把信息从源地址传输到目的地址的过程,而决定路由目标地址的是路由规则。在Dubbo里,路由规则在发起一次RPC调用前起到过滤目标服务器地址的作用,过滤后的地址列表,将作为消费端最终发起RPC调用的备选地址。它能控制流量的走向,可用于服务治理,如流量隔离、灰度发布等。

关于Dubbo路由规则的详细介绍可以直接看官方文档路由规则一小节,这里就不多叙述了,本文主要介绍下静态标签的使用与扩展。

首先区分两个概念:路由和负载均衡,在Dubbo里

路由:在不同的服务间进行分发

负载均衡:在相同服务的不同实例间进行分发

下图是Dubbo从业务中发起调用到真正执行远程调用的流程示意图,可见路由发生在负载均衡之前。

在这里插入图片描述

对应的源码在org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke中

    @Override
    public Result invoke(final Invocation invocation) throws RpcException {
        checkWhetherDestroyed();

        // binding attachments into invocation.
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        if (contextAttachments != null && contextAttachments.size() != 0) {
            ((RpcInvocation) invocation).addAttachments(contextAttachments);
        }

		//根据路由规则获取符合条件的服务
        List<Invoker<T>> invokers = list(invocation);
        //初始化负载均衡策略
        LoadBalance loadbalance = initLoadBalance(invokers, invocation);
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        //根据负载均衡策略在路由结果的服务中选择一个服务进行调用
        return doInvoke(invocation, invokers, loadbalance);
    }

启动时通过订阅注册中心的服务把符合条件的服务放在RouterChain的invokers集合里

image-20220727152938343

这里放一个静态标签路由过程的源码流程图,感兴趣的可以跟着源码走一走

路由

二、静态标签使用方法

测试时使用的Dubbo版本是2.7.3

  • 2.1 provider在应用级别打标签

    dubbo:
      scan:
        base-packages: com.restkeeper
      protocols:
        dubbo:
          name: dubbo
          port: -1
          serialization: kryo
      registry:
        address: spring-cloud://xx.xx.28.39
      consumer:
        timeout: 600000
      provider:
    #  统一版本号
        version: 1.0.0
    #    静态标签,在dubbo-admin上可以添加动态标签,动态标签优先级高于静态标签 
        tag: wyz
    

    那么在consumer端必须在对应的dubbo配置中添加标签,否则无法消费

    dubbo:
      scan:
        base-packages: com.restkeeper
      protocols:
        dubbo:
          name: dubbo
          port: -1
          serialization: kryo
      registry:
        address: spring-cloud://xx.xx.28.39
      consumer:
        timeout: 600000
        tag: wyz
      provider:
    #  统一版本号
        version: 1.0.0
    
  • 2.2 provider在接口级别打标签

    @Service(version = "1.0.0", protocol = "dubbo",tag = "wyz")
    

    consumer端有两种调用方式

    • @Reference注解里添加,这种用法写的太死

      @Reference(version = "1.0.0", check = false, tag = "wyz")
      
    • 在服务调用前使用RpcContext传递标签,例

      RpcContext.getContext().setAttachment(Constants.TAG_KEY,"wyz");
      operatorUserService.login(loginName,loginPass);
      

      显然,在每次调用RPC服务时使用RpcContext设置标签过于繁琐,官网上建议“通过 servlet 过滤器(在 web 环境下),或者定制的 SPI 过滤器设置 dubboTag”,利用servlet 过滤器有个缺点就是,如果在一次http调用中有多次RPC调用,那么除第一次外后续所有RPC调用在路由时都没有标签(每次RPC调用都会清除RpcContext的内容)。所以我们考虑利用Dubbo的SPI机制做扩展。

三、静态标签扩展

这里我们利用静态标签实现一个根据请求参数将请求分发到对应服务的功能。
先看Dubbo调用时的顺序,路由和负载选择发生在图中红色的部分

img

因此,我们可以在红色部分进行扩展,将标签信息提前放置进去。看上面调用链路图,我们只要仿照TagRouter,在TagRouter前面添加一个router专门用来添加标签信息即可。

我测试的dubbo版本是2.7.3,在这个版本的RouterFactory类上面有下面这么一段注释

 See {@link CacheableRouterFactory} and
 {@link RouterChain} for how to extend a 
 new Router or how the Router instances
 are loaded

我们看类CacheableRouterFactory,它上面又有这么一段注释

 If you want to provide a router implementation 
 based on design of v2.7.0, please extend from 
 this abstract class.For 2.6.x style router, 
 please implement and use RouterFactory directly.

这就很明显了,我们是2.7.3版本,所以直接继承CacheableRouterFactory就可以了。先创建一个用于打标签的router类,注意priority即可。

 public class GrayRouter extends AbstractRouter {
 
     public static final String NAME = "GRAY_ROUTER";
 
     /**
      * Router继承了Comparable,实现了compareTo方法基于priority进行升序排序
      * RouterChain的构造函数里基于SPI加载了所有router后会对所有的router进行排序
      * 所以,如果对router有顺序要求的话,必须设置priority的值,我们这需要比TagRouter
      * 的priority小
      */
     private static final int GRAY_ROUTER_PRIORITY = 0;
 
 
     public GrayRouter() {
         this.priority = GRAY_ROUTER_PRIORITY;
     }
     
     @Override
     public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
 
         //只是单纯地给传递标签,并不过滤invokers,TenantContext就是一个ThreadLocal,值是web拦截器拦截时保存的请求参数
         invocation.getAttachments().put(Constants.TAG_KEY, (String) TenantContext.get(Constants.TAG_KEY));
         return  invokers;
 
     }
 }

创建CacheableRouterFactory的子类

 //这里的order只能控制RouterFactory的加载顺序,并不能控制router的排序
 @Activate(order = 0)
 public class GrayRouterFactory extends CacheableRouterFactory {
 
     @Override
     protected Router createRouter(URL url) {
         return new GrayRouter();
     }
 }

然后利用Dubbo里设置好的SPI机制,在Resource路径的META-INFO/dubbo(或者dubbo/internal路径下)下创建名为org.apache.dubbo.rpc.cluster.RouterFactory的文件,文件内容是

 gray=com.restkeeper.dubbo.GrayRouterFactory

然后我们就可以测试了,这里我们把标签信息放到请求头上,然后在web拦截器里保存一下

image-20220801160005107

测试接口,请求头带标签

image-20220801162754880

请求头不带标签,因为我没有专门起一个不带标签的服务,所以路由降级的时候直接报找不到服务

image-20220801160630142

在GrayRouter里,我们把标签信息放到了ThreadLocal里,所以只要是一次http请求,在一个线程里,无论多少次RPC调用都能设置上标签。

此外,如果需要将标签信息在服务链路中传递,那么可以扩展Filter,设置一个ConsumerFilter在服务调用时把标签信息保存到invocation的attachment里,设置一个和ProviderFilter在服务被调用时保存到ThreadLocal里,扩展的流程可参考调用拦截扩展,这里就不写了,注意一个点就行,在dubbo的ContextFilter里,它会unloading一些特定的参数,像我们上面的Constants.TAG_KEY都会被清掉,所以标签的名字要注意别跟会unloading的参数名一样,或者干脆设置扩展的filter执行顺序在ContextFilter后面。

最后说一下,路由和version与group的区别,version与group有点像静态的路由,如果服务的version和group不匹配,那么它就不会出现在RouterChain的invokers集合里,而路由,由于降级策略,即使有不匹配标签的服务也会出现在invokers里,而且路由规则是在每次RPC调用时都会执行的。

参考:
1.Dubbo路由功能实现灰度发布及源码分析
2.深入理解RPC框架原理与实现 华钟明著

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dubbo路由规则:静态标签的使用与扩展 的相关文章

随机推荐

  • Navicat for MySQL 连接 Mysql 8.0.11 出现1251- Client does not support authentication protocol 错误

    1 打开cmd 进入mysql 2 依次输入以下命令 ALTER USER root localhost IDENTIFIED BY password PASSWORD EXPIRE NEVER 修改加密规则 ALTER USER root
  • 浅谈matlab数学建模中@符号-----函数句柄

    很多刚开始学数学建模的小伙伴第一次在matlab程序中遇到 这个符号都不知道是什么意思 如 f myfunction 或者 fun sin 其实这种用法叫创建函数句柄 当我们在万能的matlab帮助文档搜索函数句柄 什么花里胡哨的 打开即劝
  • zlib导入到工程与数据压缩

    一 将zlib导入到工程中 1 编译zlib库后 会生成一个ZlibDllRelease文件夹 Release版本 和一个ZlibDllDebug文件夹 Debug版本 使用zlib库 共需4个文件 zlib 1 2 8的根目录下的zcon
  • vue-cli-service serve --open启动项目时打开浏览器失效无法打开浏览器解决方法

    当在vue项目中的package json文件修改启动命令时 发现也无法自动打开浏览器 scripts serve vue cli service serve open build vue cli service build npm run
  • Python正则表达式模块(re)简介

    author skate time 2014 10 13 Python正则表达式模块 re 简介 一 Python中转义字符 正则表达式使用反斜杠 来代表特殊形式或用作转义字符 这里跟Python的语法冲突 因此 Python用 表示正则表
  • nginx 使用教程

    一 win7 nginx 常用命令 1 启动nginx start nginx 2 nginx 服务器重启命令 关闭 nginx s reload 修改配置后重新加载生效 nginx s reopen 重新打开日志文件 nginx t c
  • RabbitMQ应用之消息堆积、消息丢失、有序消费、重复消费

    文章目录 前言 一 消息堆积 1 消息堆积的产生与影响 2 消息堆积的解决方案 二 消息丢失 1 情景 2 解决方案 三 有序消费 1 情景 2 解决方案 四 重复消费 1 情景 2 解决方案 前言 最近接触了多线程和MQ等性能相关的内容
  • HTML 特殊符号编码对照表

    特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码 特殊符号 命名实体 十进制编码 Alpha 913 Beta 914 Gamma 915 Delta 916 Epsilon 917 Zeta 918 Eta 919 Thet
  • 工业互联网产业链全景图深度分析

    工业互联网领域有哪些投资机会 新基建 是与传统基建相对应 结合新一轮科技革命和产业变革特征 面向国家战略需求 为经济社会的创新 协调 绿色 开放 共享发展提供底层支撑的具有乘数效应的战略性 网络型基础设施 其中 新基建 包括5G基建 特高压
  • openwrt 修改feeds.conf.default为GitHub源

    lede和openwrt合并之后 lede官网挂了 git openwrt org 也访问不了 只好去github上找最新源码 git clone https github com openwrt openwrt git 复制代码 最新的l
  • 嵌入式linux 配置usb otg,嵌入式系统设计中的USB OTG方案

    速外设操作时最大为80mA TD1120整个芯片支持功率节省模式 包括主机控制器以及外设控制器的延缓模式以使功率消耗最小化www cechina cn 延长系统电池寿命 对于移动设备来说 电池寿命是很关键的性能 接口性能表现 USB数据传输
  • Bitmap之压缩方案

    文章目录 前言 1 基础知识 1 1色彩模式 1 2四种模式的区别 1 3具体对比 1 4bitmap内存占用大小计算方式 1 5图片存在的形式 1 6BitampFactory加载Bitmap对象的方式 2 压缩方案 2 1采样率压缩 2
  • Bugku 计算器

    首先打开题目链接 发现一个式子 但答案有三位数 而只能输入一个数字 直接F12查看原代码 发现maxlenthen 1 maxlenthen意思是文件域可接受的字符数量的上限 可输入字符串最大的长度 容质 所以把1改为3就好啦 然后得到fl
  • Redisson源码-多线程之首个获取锁的线程加解锁流程

    Redisson源码 多线程之首个获取锁的线程加解锁流程 简介 当有多个线程同时去获取同一把锁时 第一个获取到锁的线程会进行加解锁 其他线程需订阅消息并等待锁释放 以下源码分析基于redisson 3 17 6版本 不同版本源码会有些许不同
  • openEuler 20.03 LTS SP2以及SP3安装完gnome后,gdm登陆进入不了桌面问题

    一 问题原因 是由于CVE 2020 17489相关补丁引入的 暂不清楚是何原因造成 但除去该相关补丁之后 该问题消失 在网上查了下 CVE 2020 17489的问题是gnome shell的某些配置中会发现 注销账户时 登陆对话框中的密
  • SQLI-Labs(15-17)

    目录 15关 16关 17关 15关 看到这个那么我们可以首先尝试报错或者盲注 payload or length database 8 qwe 在这里我们发现and 会报错 跟之前我们利用and爆错不一样 那为什么这里我们在post传参时
  • Dubbo是什么

    Dubbo是什么 Dubbo是一个分布式服务框架 致力于提供高性能和透明化的RPC远程服务调用方案 以及SOA服务治理方案 简单的说 dubbo就是个服务框架 如果没有分布式的需求 其实是不需要用的 只有在分布式的时候 才有dubbo这样的
  • 统计oracle 数据库 lawpeople表lawtype字段多个值只统计一次问题,按照地区分类

    select temparea name case when lawtype like 501 then 501 when lawtype like 502 then 502 when lawtype like 503 then 503 w
  • CSR867x — 如何看懂一份psr文件

    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX 作 者 文化人 XX 联系方式 XX 版权声明 原创文章 欢迎评论和转载 转载时能告诉我一声就最好了 XX 要说的话 作者
  • Dubbo路由规则:静态标签的使用与扩展

    一 路由的流程 路由是通过互联网把信息从源地址传输到目的地址的过程 而决定路由目标地址的是路由规则 在Dubbo里 路由规则在发起一次RPC调用前起到过滤目标服务器地址的作用 过滤后的地址列表 将作为消费端最终发起RPC调用的备选地址 它能