⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 知了一笑 「知了一笑」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

让请求在导航的服务节上点执行;

一、背景简介

分布式系统中会存在这样的开发场景,不同需求可能涉及到对同一个服务的开发,那么该服务在研发期间就会存在多个版本并行的状态,为了保持不同版本之间的隔离性,验收需要将请求路由到指定版本号的服务上处理;

假设存在三个服务:A、B、C,且服务B和C都存在多个版本,那么让请求按照即定的路由规则执行,即可保证研发期间的验收是版本间隔离的,并且可以实现灰度部署的策略;

二、负载策略

在微服务系统架构中,请求在服务间转发时会执行负载的策略,尤其当服务存在多版本号的集群模式时,很显然常规的轮询、权重、随机等策略无法满足需求;进行路由规则的自定义设计和开发是常见方式;

经典应用场景:在请求发起时,可以通过Header、Cookie、Parameter等不同的方式,携带路由规则的方式与参数执行匹配逻辑,从而将请求路由到指定版本的服务;

默认主分支路由

通常来说请求会在主干分支上执行,或者其他分支路由规则不匹配,也可以通过标识配置,判断是否由主分支兜底,甚至是存活的任意服务兜底;

存活的服务中可能存在多个版本,但是主分支Master是否存活是服务健康与否的基本标志,常规应用中路由规则如果不匹配,会由Master服务进行兜底;

版本号统一路由

请求通过携带分支号进行统一版本路由是常用的轻量级方案,即如果请求携带的是2.0.0的分支,则在路由时优先匹配相关版本的服务,不匹配时由Master服务处理即可;

服务定制化路由

在请求或配置中指定各个服务的路由分支号,也是常见的匹配方案,如上图在请求时指定服务B由1.0.0分支执行,服务C由3.0.0分支执行,其余服务在主干分支执行;

路由规则可以看做是对可用服务的匹配筛选,如果筛选出来的服务存在集群部署时,还要去执行相应的负载均衡策略,例如上图中当服务C的3.0.0分支是集群时,路由匹配到该版本后,再通过负载均衡的策略选中其中一个服务处理请求;

三、灰度部署

当负载均衡的策略可以按照定制化开发的规则执行时,那服务的灰度发布就会容易很多,在不影响现有服务的情况下发布新版本,同时将请求按照规则分流,完成对新服务的验收后,替换掉旧版本即可;

分布式系统中子服务的拆分非常多,版本开发通常只会涉及其中部分子服务,通过灰度模式将相关服务部署到线上,并且不会影响主干的服务,只有开启特定的配置才会将请求分流到灰度服务;

流程细节

  • 1、做好路由配置和管理,请求默认在主干服务执行;
  • 2、部署版本涉及的相关服务,灰度层面默认不会处理请求;
  • 3、验收阶段基于配置,将指定规则的请求路由到灰度层;
  • 4、常用规则:携带分支号、灰度用户群、比例分流、IP等;
  • 5、完成灰度服务验收后,将相关服务标记为主干服务;
  • 6、将旧的主干服务下线后,即本次上线流程完整结束;
  • 7、若发现灰度服务验收失败,撤掉灰度层或修改都可以;

灰度发布的模式即依赖于自定义的路由规则,以及服务在负载均衡时权重比例倾斜,这些都可以在配置中心管理,在测试时动态修改即可;

在这种模式下,灰度服务的上线或者下线几乎是没有明显感知的,如果是相对简单的流程,由测试人员验收灰度层服务即可,如果是复杂的流程,放开一定比例的用户流量,流程观察没有问题后完成升级;

四、实践方案

1、流程设计

在灰度方案落地实践的过程中,通常客户端会携带路由规则的标识,从而将请求发送到指定服务,在规则无法正常匹配的时候,由主干服务处理,对于一些核心的开关标识在配置中心统一维护;

2、路由标识

标识获取

通常情况下,路由的标识是在请求头中携带的,这样比较方便统一管理,常用的传递格式如下:

  • 版本号统一路由:routeId:2.0.0,即所有请求优先在2.0.0分支执行;
  • 服务定制化路由:serverC:3.0.0,请求服务C时优先在3.0.0分支执行;

在微服务的组件中获取请求头的方式很多,比如Gateway网关中的路由过滤器,或者服务中的拦截器,都可以获取请求的相关参数信息,从而执行路由规则;

标识管理

自定义路由规则需要客户端标识,虽然获取请求中的标识并不复杂,但是将标识传递到路由规则中就涉及到上下文参数管理:

  • 写阶段:在过滤或拦截中获取路由标识,写入上下文容器;
  • 读阶段:路由时从容器中读取标识,基于配置信息执行规则;

请求从进入网关开始,在服务间通信时会涉及负载均衡的策略,在过滤或拦截器中将标识写到上下文容器,执行路由规则需要读取上下文容器,如果标识不存在则默认选择主干服务执行请求;

3、服务选中

微服务之间通信时,选中一个服务执行请求的逻辑比较复杂,尤其在灰度模式下涉及到对路由规则的改造,即策略指定的服务优先被选中;

  • 1、从注册中心查询相应服务的可用列表;
  • 2、基于路由规则,匹配符合请求标识的服务;
  • 3、对筛选的结果列表执行负载均衡,选中服务;

在整个路由机制中,会涉及到匹配规则自定义改造,从常规的手段来看,将版本的分支号加载到服务的元数据信息中,再结合服务名称或者IP地址,来实现对服务列表的多维度过滤,可以支撑大部分轻量级灰度策略的实现。

五、参考源码

应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent

组件封装:
https://gitee.com/cicadasmile/butte-frame-parent

文章目录
  1. 1. 一、背景简介
  2. 2. 二、负载策略
  3. 3. 三、灰度部署
  4. 4. 四、实践方案
    1. 4.1. 1、流程设计
    2. 4.2. 2、路由标识
    3. 4.3. 3、服务选中
  5. 5. 五、参考源码