灰度发布 of【速成架构师】

1 背景

想要成为架构师,必须了解灰度发布,不能粗暴的全量发布,全量发布会带来太多问题,如:

  • 一旦新版本存在BUG,将影响所有用户
  • 一旦发布时出现问题,将中断服务,影响甚大
  • ...

反之,灰度发布不仅可以解决以上问题,还能有以下优势:

  • 有效降低风险:通过将版本部署到少数用户中,有效减少新版本的风险,降低线上故障的概率
  • 快速回滚:通过灰度发布,一旦发现新版本存在问题,可以快速回滚到旧版本,降低线上故障对用户的影响
  • 增强用户的体验:在灰度发布的过程中,可以及时获取用户的反馈,根据反馈及时优化新版本功能,提升用户体验
  • 提升开发效率:通过灰度发布,可以使得每次上线的范围更小,减少测试排查的时间,缩短开发周期

所以,"精通"灰度发布是架构师的必要技能之一。

2 基础知识

2.1 灰度发布分类

策略名称 简介 缺点
蓝绿 同时部署蓝、绿相同两套环境,发布时只更新未使用的环境,发布后将流量切至此次发布的环境 - 资源浪费 - 全量切换,故障范围影响大
金丝雀 按照比例对流量进行分发,比例由少到多,同时逐步对新环境扩容和对老环境缩容 - 发布周期长,运维工作大 - 无差别灰度,可能影响VIP用户
ABTest 基于用户请求的元信息,对流量进行分发,只有特定用户的流量路由到新版本,经观察稳定后,流量全量路由到新版本 - 资源浪费- 发布周期长,运维工作大

2.2 蓝绿发布架构

蓝绿发布的的部署架构图如下:

本文的重点是灰度发布,如何部署应用并且部署两套不在本文的介绍中。

当部署两套环境后,要实现无感蓝绿发布,核心是在用户与应用之间部署一个网关,在网关上配置路由规则,网关根据配置将流量全部引向绿环境或者蓝环境。

蓝绿环境会共用数据层的数据库、搜索引擎等,因此蓝绿环境必须兼容数据层,否则不能实现来回蓝绿切换

2.3 金丝雀

金丝雀发布架构与蓝绿架构基本相同,唯一的区别是网关对流量的分发规则不同,金丝雀的网关根据流量比例,将流量分别路由至蓝环境或者绿环境,并逐步扩大到新环境的流量比例,直至100%。在这个过程中,应用可以控制两边的服务资源,避免浪费。

2.4 ABTest

ABTest整体架构与蓝绿架构基本相同,唯一的区别是网关对流量的分发规则不同,ABTest的网关会将带有流量标记的路由到蓝环境,当经过一定周期的观察,确认蓝环境稳定后,即可将所有的请求路由到蓝环境。因为灰度过程已验证蓝环境的稳定性,此时是可以下线或缩容绿环境的服务,避免浪费资源。

不同的业务系统,流量标记规则不同,以企业B端SaaS软件为例,可以有以下规则:

  • 以员工ID为标记
  • 以机构ID为标记
  • 以岗位为标记
  • ...

可以发现,以上都是以员工的属性为标记,实际场景中还可以浏览器版本、网络IP为标记规则。

网关通常不负责流量标记,网关只负责根据流量标记进行路由分发。因此在ABTest发布中,尤为重要的一点就是如何对流量进行标记。

最常见的的流量标记实现方式就是cookie,例如cookie中GrayMark=true时则代表处于灰度中,访问的是蓝环境,反之则不是。

那如何对流量进行标记呢?不同的架构、场景实现方式都不相同,这里举例一个场景:机构ID为A、员工范围在【B、C】的进行标记,访问蓝环境。

上述场景是以员工的属性为标记,因此流量打标应当是在感知到用户身份时进行,假设系统对接了认证中心,那就很好实现了,时序图如下:

2.5 全链路灰度

3 SpringCloudGateway

SpringCloudGateway的一个API网关项目,基于Spring5.0 + SpringBoot2.0 + WebFlux(基于⾼性能的Reactor模式响应式通信框架Netty,异步⾮阻塞模型)等技术开发。

本节将举例一个典型场景,通过SpringCloudGateway分别实现蓝绿发布、ABTest和金丝雀发布。

以前后端分离、后端微服务架构为例,假设应用包含2个前端服务和2个后端服务,首先部署绿环境,得到各服务地址如下:

再次部署蓝环境,得到各服务地址如下:

然后部署SpringCloudGateway,得到网关服务地址如下:

3.1 蓝绿发布

网关的路由规则需要配置两套,流量路由至绿环境的配置如下:

SpringCloudGateway详细配置

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: front1
          uri: http://0.0.0.1:4200
          order: 1
          predicates:
            - Path=/front1/**
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.2:4200
          order: 1
          predicates:
            - Path=/front2/**
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.1:8080
          order: 1
          predicates:
            - Path=/server1/**
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.2:8080
          order: 1
          predicates:
            - Path=/server2/**
          filters:
            - StripPrefix=1

流量路由至蓝环境的配置如下:

SpringCloudGateway详细配置

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: front1
          uri: http://0.0.0.3:4200
          order: 1
          predicates:
            - Path=/front1/**
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.4:4200
          order: 2
          predicates:
            - Path=/front2/**
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.3:8080
          order: 3
          predicates:
            - Path=/server1/**
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.4:8080
          order: 4
          predicates:
            - Path=/server2/**
          filters:
            - StripPrefix=1

SpringCloudGateway网关进行蓝绿配置切换时,不能影响正在使用的用户,因此不建议使用重启网关更新配置的方法,可以通过nacos配置中心动态更新网关路由配置 。( PS:即使网关支持滚动发布,也不建议重启更新,网关作为入口中间件,应尽可能减少变更的次数

3.2 金丝雀发布

SpringCloudGateway要实现按比例路由,需要使用权重配置,例如80%的流量路由至绿环境,20%的流量路由至蓝环境,配置如下:

SpringCloudGateway详细配置

ini 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: front1
          uri: http://0.0.0.1:4200
          order: 1
          predicates:
            - Path=/front1/**
            - Weight=front1,8
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.2:4200
          order: 1
          predicates:
            - Path=/front2/**
            - Weight=front2,8
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.1:8080
          order: 1
          predicates:
            - Path=/server1/**
            - Weight=server1,8
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.2:8080
          order: 1
          predicates:
            - Path=/server2/**
            - Weight=server2,8
          filters:
            - StripPrefix=1

        - id: front1
          uri: http://0.0.0.3:4200
          order: 1
          predicates:
            - Path=/front1/**
            - Weight=front1,2
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.4:4200
          order: 1
          predicates:
            - Path=/front2/**
            - Weight=front2,2
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.3:8080
          order: 1
          predicates:
            - Path=/server1/**
            - Weight=server1,2
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.4:8080
          order: 1
          predicates:
            - Path=/server2/**
            - Weight=server2,2
          filters:
            - StripPrefix=1

问题:同一个用户访问时,按照权重分发流量,可能有时访问的是蓝环境、有时访问的是绿环境,甚至同一次页面访问,不同的请求都会路由到不同的环境中去,如何解决?nginx支持iphash与权重的结合使用,SpringCloudGateway似乎不支持ip hash

3.3 ABTest

SpringCloudGateway要实现按标记路由,例如默认路由至绿环境,带有标记cookie:GrayMark=true的路由至蓝环境,配置如下:

SpringCloudGateway详细配置

ini 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: front1
          uri: http://0.0.0.1:4200
          order: 2
          predicates:
            - Path=/front1/**
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.2:4200
          order: 2
          predicates:
            - Path=/front2/**
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.1:8080
          order: 2
          predicates:
            - Path=/server1/**
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.2:8080
          order: 2
          predicates:
            - Path=/server2/**
          filters:
            - StripPrefix=1

        - id: front1
          uri: http://0.0.0.3:4200
          order: 1
          predicates:
            - Path=/front1/**
            - Cookie=GrayMark,true
          filters:
            - StripPrefix=1
        - id: front2
          uri: http://0.0.0.4:4200
          order: 1
          predicates:
            - Path=/front2/**
            - Cookie=GrayMark,true
          filters:
            - StripPrefix=1
        - id: server1
          uri: http://1.0.0.3:8080
          order: 1
          predicates:
            - Path=/server1/**
            - Cookie=GrayMark,true
          filters:
            - StripPrefix=1
        - id: server2
          uri: http://1.0.0.4:8080
          order: 1
          predicates:
            - Path=/server2/**
            - Cookie=GrayMark,true
          filters:
            - StripPrefix=1

针对蓝环境的路由配置都加上了Cookie=GrayMark,true,并且order都为1,比绿环境的配置先判断。如果是绿环境先判断,那所有的流量就会被绿环境路由。

4 nginx网关

nginx是一个高性能的HTTP和反向代理web服务器,具有高稳定性、多功能、门槛低和消耗低等特点

本节将举例一个典型场景,通过nginx分别实现蓝绿发布、ABTest和金丝雀发布。

以前后端分离、后端微服务架构为例,假设应用包含2个前端服务和2个后端服务,首先部署绿环境,得到各服务地址如下:

再次部署蓝环境,得到各服务地址如下:

然后部署nginx,得到网关服务地址如下:

4.1 蓝绿发布与金丝雀发布

nginx.conf配置如下:

nginx详细配置

ini 复制代码
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    upstream front1{
        ip_hash;
        server http://0.0.0.1:4200 down;
        server http://0.0.0.3:4200 weight=100;
    }

    upstream front2{
        ip_hash;
        server http://0.0.0.2:4200 down;
        server http://0.0.0.4:4200 weight=100;
    }

    upstream server1{
        ip_hash;
        server http://1.0.0.1:8080 down;
        server http://1.0.0.3:8080 weight=100;
    }

    upstream server2{
        ip_hash;
        server http://1.0.0.2:8080 down;
        server http://1.0.0.4:8080 weight=100;
    }

    server{
        listen 8888;
        server_name gateway;

        location /front1/ {
            proxy_pass http://front1/;
        }
        location /front2/ {
            proxy_pass http://front2/;
        }
        location /server1/ {
            proxy_pass http://server1/;
        }
        location /server2/ {
            proxy_pass http://server2/;
        }
    }

}

上述配置主要是通过upstream的权重参数进行蓝绿流量的路由,若要实现金丝雀发布,只需要再对不同upstream的权重调整即可。

4.2 ABTest

nginx详细配置

perl 复制代码
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    map $COOKIE_GrayMark $front1 {
        ~*true$ front1_blue;
        default front1_green;
    }

    upstream front1_green{
        server http://0.0.0.1:4200;
    }

    upstream front1_blue{
        server http://0.0.0.3:4200;
    }

    map $COOKIE_GrayMark $front2 {
        ~*true$ front2_blue;
        default front2_green;
    }

    upstream front2_green{
        server http://0.0.0.2:4200;
    }

    upstream front2_blue{
        server http://0.0.0.4:4200;
    }

    map $COOKIE_GrayMark $server1 {
        ~*true$ server1_blue;
        default server1_green;
    }

    upstream server1_green{
        server http://1.0.0.1:8080;
    }

    upstream server1_blue{
        server http://1.0.0.3:8080;
    }

    map $COOKIE_GrayMark $server2 {
        ~*true$ server2_blue;
        default server2_green;
    }

    upstream server2_green{
        server http://1.0.0.2:8080;
    }

    upstream server2_blue{
        server http://1.0.0.4:8080;
    }

    server{
        listen 8888;
        server_name gateway;

        location /front1/ {
            proxy_pass http://$front1/;
        }
        location /front2/ {
            proxy_pass http://$front2/;
        }
        location /server1/ {
            proxy_pass http://$server1/;
        }
        location /server2/ {
            proxy_pass http://$server2/;
        }
    }

}

上述配置是以cookie:GrayMark=true的流量固定分配至蓝环境。

参考资料:

baijiahao.baidu.com/s?id=177176...

juejin.cn/post/708924...

www.python100.com/html/104577...

juejin.cn/post/708814...

juejin.cn/post/704990...

docs.spring.io/spring-clou...

blog.csdn.net/weixin_4393...

baike.baidu.com/item/nginx/...

zhuanlan.zhihu.com/p/590072814...

www.cnblogs.com/h-c-g/p/109...

my.oschina.net/u/4586970/b...

相关推荐
重整旗鼓~25 分钟前
2.flask中使用装饰器统一验证用户登录
后端·python·flask
bohu831 小时前
快速搭建springcloud 3.X+mybatis+nacos本地项目
spring cloud·nacos·mybatis
it噩梦1 小时前
springboot 工程使用proguard混淆
java·spring boot·后端
从种子到参天大树2 小时前
SpringBoot源码阅读系列(二):自动配置原理深度解析
后端
狠难说2 小时前
SpringCloud(八) - 自定义token令牌,鉴权(注解+拦截器),参数解析(注解+解析器)
后端
从种子到参天大树2 小时前
SpringBoot源码阅读系列(一):启动流程概述
后端
m0_748254882 小时前
Spring Boot实现多数据源连接和切换
spring boot·后端·oracle
庄周de蝴蝶2 小时前
一次 MySQL IF 函数的误用导致的生产小事故
后端·mysql
韩数3 小时前
Nping: 支持图表实时展示的多地址并发终端命令行 Ping
后端·rust·github
18号房客3 小时前
云原生后端开发(一)
后端·云原生