# 蓝绿滚动灰度发布 **Repository Path**: hgh411/release-demo ## Basic Information - **Project Name**: 蓝绿滚动灰度发布 - **Description**: =====蓝绿、滚动、灰度发布===== - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-04-18 - **Last Updated**: 2024-04-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 蓝绿、滚动、灰度发布 ## 1 蓝绿、滚动、灰度发布概念 应用程序升级面临最大挑战是新旧业务切换,将软件从测试的最后阶段带到生产环境,同时要保证系统不间断提供服务 长期以来,业务升级渐渐形成了几个发布策略:蓝绿发布、灰度发布和滚动发布,目的是尽可能避免因发布导致的流量丢失或服务不可用问题 ### 1.1 蓝绿发布 Blue-Green Deployment #### 概念 指同时运行两个版本的应用,部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上 ![BlueGreenDeployment.png](img/BlueGreenDeployment.png) #### 优点 发布策略简单 用户无感知,平滑过渡 升级/回滚速度快 #### 缺点 如果出问题,影响范围较大 成本较高 ### 1.2 滚动发布 Rolling Release #### 概念 每次只升级一个或多个服务,升级完成后加入生产环境,不断执行这个过程,直到集群中的全部旧版本升级新版本 滚动发布能够解决掉蓝绿部署时对硬件要求增倍的问题,也可以使用临时一台或多台服务器进行替换 ![RollingRelease.png](img/RollingRelease.png) #### 优点 用户无感知,平滑过渡 如果出问题,影响范围较小 节约资源 #### 缺点 部署时间慢,取决于每阶段更新时间 发布策略较复杂 无法确定没问题的环境,不易回滚 ### 1.3 灰度发布 Gray Release(又名金丝雀发布 Canary Release) #### 概念 只升级部分服务,即让一部分用户继续用老版本,一部分用户开始用新版本,如果用户对新版本没什么意见,那么逐步扩大范围,把所有用户都迁移到新版本上面来 ![GrayRelease.png](img/GrayRelease.png) #### 优点 保证整体系统稳定性,在初始灰度的时候就可以发现、调整问题,影响范围可控 新功能逐步评估性能,稳定性和健康状况,如果出问题影响范围很小,相对用户体验也少 用户无感知,平滑过渡 #### 缺点 流量配比递增的配置修改,带来额外的操作成本 用户覆盖狭窄,低比例流量未必能发现所有问题 ## 2 网关和服务调用蓝绿、灰度发布实践(基于 consul、gateway、ribbon、loadbalancer、openfeign) 当调用请求从网关或者服务发起的时候,通过 Header、Parameter、Cookie 一种或者几种参数进行驱动,在路由过滤中,根据这些参数实现路由的规则策略,并且全链路需要传递版本信息 以如下调用链为例,两个调用处做修改,一处为网关,一处为服务间调用,使用 header 加 version 的方式,其余方式同理 ![CallChain.png](img/CallChain.png) ### 2.1 服务注册版本号 由于需要对服务器进行标记版本号,在此介绍基于 consul 的配置,需要在服务的配置文件中加如下配置 ```properties spring.cloud.consul.discovery.tags=version=V1 ``` 增加后,在 consul 控制台中能看到如下配置 ![ConsulDashboard.png](img/ConsulDashboard.png) 服务发现即可获取到此配置 服务发现其实可以使用 spring.cloud.consul.discovery.server-list-query-tags 配置来发现指定标记的服务,但是不利于动态修改,不使用此方法 ### 2.2 网关修改 如果 gateway 集成了 ribbon,则服务调用负载均衡使用的时 ribbon,否则使用的是 loadbalancer,可通过如下配置修改,默认为 true ```properties spring.cloud.loadbalancer.ribbon.enabled=false ``` 下面已两种方式分别介绍 #### gateway + ribbon gateway + ribbon 路由调用链 ![GatewayRibbonChain.png](img/GatewayRibbonChain.png) 基于 ribbon 的负载均衡默认网关拦截器为 org.springframework.cloud.gateway.filter.LoadBalancerClientFilter 我们可以重写 choose( ServerWebExchange exchange) 方法,来支持拦截请求头,做规则逻辑,见 com.baidb.gateway.ribbon.filter.GrayLoadBalancerClientFilter 类 ribbon 的负载均衡规则需要支持服务选择,在此通过继承 com.netflix.loadbalancer.RoundRobinRule 实现轮询规则,见 com.baidb.gateway.ribbon.rule.RibbonServerDiscoveryRule 类 配置类使过滤器和规则生效,见 com.baidb.gateway.ribbon.configuration.RibbonConfiguration 类 #### gateway + loadbalancer gateway + loadbalancer 调用链 ![GatewayLoadbalancerChain.png](img/GatewayLoadbalancerChain.png) 基于 loadbalancer 的默认网关拦截器为 org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter 我们可以重写此类支持拦截请求头,见 com.baidb.gateway.reactive.filter.GrayReactiveLoadBalancerClientFilter 类,主要重写 createRequest() 方法,将请求头传递到 loadbalancer 默认的 loadbalancer 实现为 org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer,仿照此类,我们实现见 com.baidb.gateway.reactive.loadbalancer.GrayReactiveRoundRobinLoadBalancer 类,主要方法 processInstanceResponse() 配置类使过滤器和负载均衡器生效,见 com.baidb.gateway.reactive.configuration.ReactiveLoadBanlancerConfiguration 类 ### 2.2 服务间调用修改 openfeign + ribbon 服务间调用链 ![OpenfeignRibbonChain.png](img/OpenfeignRibbonChain.png) 跟据调用链,我们需要在 openfeign 请求时请求头增加 version,并且在调用 IRule 时,根据上下文 version,选择服务,上下文绑定参数可以使用 java.lang.InheritableThreadLocal 进行绑定参数 首先需要使用 aop 在 openfeign 调用前,绑定参数,请求后,清除参数,见 com.baidb.service2.aspect.FeignRibbonFilterInterceptor 类 openfeign 请求时,在请求头增加 version,见 com.baidb.service2.feign.FeignHeadersInterceptor 类 重写 IRule 实现服务选择,见 com.baidb.service2.ribbon.RibbonServerDiscoveryRule 类 配置类见 com.baidb.service2.configuration.OpenFeignConfiguration 类和 com.baidb.service2.configuration.OpenFeignClientsConfiguration 类