灰度发布 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...

相关推荐
Asthenia04125 分钟前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom6 分钟前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
Asthenia04121 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9651 小时前
ovs patch port 对比 veth pair
后端
Asthenia04122 小时前
Java受检异常与非受检异常分析
后端
uhakadotcom2 小时前
快速开始使用 n8n
后端·面试·github
JavaGuide2 小时前
公司来的新人用字符串存储日期,被组长怒怼了...
后端·mysql
bobz9652 小时前
qemu 网络使用基础
后端
Asthenia04123 小时前
面试攻略:如何应对 Spring 启动流程的层层追问
后端
Asthenia04123 小时前
Spring 启动流程:比喻表达
后端