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个后端服务,首先部署绿环境,得到各服务地址如下:
- 前端服务绿1:http://0.0.0.1:4200
- 前端服务绿2:http://0.0.0.2:4200
- 后端服务绿1:http://1.0.0.1:8080
- 后端服务绿2:http://1.0.0.2:8080
再次部署蓝环境,得到各服务地址如下:
- 前端服务蓝1:http://0.0.0.3:4200
- 前端服务蓝2:http://0.0.0.4:4200
- 后端服务蓝1:http://1.0.0.3:8080
- 后端服务蓝2:http://1.0.0.4:8080
然后部署SpringCloudGateway,得到网关服务地址如下:
3.1 蓝绿发布
网关的路由规则需要配置两套,流量路由至绿环境的配置如下:
- http://2.0.0.0:8888/front1/** :http://0.0.0.1:4200
- http://2.0.0.0:8888/front2/** :http://0.0.0.2:4200
- http://2.0.0.0:8888/server1/** :http://1.0.0.1:8080
- http://2.0.0.0:8888/server2/** :http://1.0.0.2:8080
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
流量路由至蓝环境的配置如下:
- http://2.0.0.0:8888/front1/** :http://0.0.0.3:4200
- http://2.0.0.0:8888/front2/** :http://0.0.0.4:4200
- http://2.0.0.0:8888/server1/** :http://1.0.0.3:8080
- http://2.0.0.0:8888/server2/** :http://1.0.0.4:8080
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个后端服务,首先部署绿环境,得到各服务地址如下:
- 前端服务绿1:http://0.0.0.1:4200
- 前端服务绿2:http://0.0.0.2:4200
- 后端服务绿1:http://1.0.0.1:8080
- 后端服务绿2:http://1.0.0.2:8080
再次部署蓝环境,得到各服务地址如下:
- 前端服务蓝1:http://0.0.0.3:4200
- 前端服务蓝2:http://0.0.0.4:4200
- 后端服务蓝1:http://1.0.0.3:8080
- 后端服务蓝2:http://1.0.0.4:8080
然后部署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...
www.python100.com/html/104577...
baike.baidu.com/item/nginx/...
zhuanlan.zhihu.com/p/590072814...