金丝雀发布的本质
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了金丝雀发布的本质相关的知识,希望对你有一定的参考价值。
参考技术A 金丝雀发布在国内也经常被叫做灰度发布。下文将使用”金丝雀发布“这一术语。金丝雀发布是发布模式的一种。“发布”是什么意思?发布:即宣布,发表。有向外公开的意思。
说到“发布”,就不得不说“部署”。不少人将“发布”与“部署”两个概念混淆。
“部署”又是什么意思?在软件工程领域,“部署”指的是将(编译)打包好的程序发送到目标服务器上,并启动执行。
就是说,部署了,并不一定代表着向用户发布。
如果把软件产品比喻成一舞台剧。部署是将舞台提前布置好,但是幕布是拉上的。而发布则是把观众放进剧场,然后拉开幕布。注意:只有真正“拉开幕布”,才称为发布。
那金丝雀发布又是什么?接着刚刚说的比喻,指的是你并不是一次性将所有的观众都放进剧场。只是有条件的让一部分人进场并拉开幕布。你可以通过这些观众对于舞台剧的评价对舞台剧进行调整改进。最后,再选择合适的时机向所有的人开放消费。
回到技术领域。金丝雀发布就是你已经将程序部署到生产环境了,然后根据流量比例、用户ID、用户地域、用户类型等不同维度的条件,允许用户使用部署到生产环境上的程序上的功能。这个过程中,你可以观察这些”特权“用户的数据,以判断你是否需要对功能进行改进。当数据足以支撑全量发布时,就可以进行全量发布。
这就是我们文章开头强调的:金丝雀发布是发布模式的一种。以下是根据流量比例进行金丝雀发布的图示(来自flagger.app):
Flagger是一种基于K8s的发布控制器。能以较低的成本实现金丝雀发布。本例中,它启动一个V2版本的程序的实例,并”放行“5%的用户请求进入V2版本的实例。
因为软件产品一次性全量发布后,你并不能确保它一定受大众喜爱,所以,一步步的试探用户的喜好的软件产品发布策略成为必然选择。
比起一次性全量发布,金丝雀是一种演进式的发布模式,也可以说是一种业务级别的决策。
说到”目的“,就不得不说与金丝雀发布容易混淆的”蓝绿部署“。
蓝绿部署也是一种发布模式。如下图。它的部署方式与金丝雀发布的部署方式几乎一样。
蓝绿部署与金丝雀发布之间存在两个区别。主要区别是”目的“。蓝绿部署的发布模式的目的是更安全的部署,金丝雀发布的目的是演进式的发布。
次要区别是决策维度的不同。蓝绿部署是技术维度的决策,而金丝雀是业务维度的决策。
如下图展示的是蓝绿部署的决策过程。如果V2版本的实例在生产环境经过多种验证方式验证过,即可把流量全部切到V2版本。在验证期间会保留V1实例,以保证可以随时回滚。
另,至于为什么是叫蓝绿部署(Blue-Green Deployments)而不是蓝绿发布。个人认为是因为从一开始蓝绿部署的出发点是零停机(Zero Downtime),而不是演进式的发布。当然,从名称上也体现了在蓝绿部署和金丝雀发布在”决策维度“上的区别。
参考Martin Fowler关于蓝绿部署的文章: https://martinfowler.com/bliki/BlueGreenDeployment.html
容易与金丝雀发布混淆的,还有”滚动更新“。它是一种将软件程序从一个版本平滑的升级到另一个的版本部署技术。如下图。属于技术决策。与业务无关。与金丝雀发布不是同一个维度的东西。
动态图来自: https://www.bluematador.com/blog/kubernetes-deployments-rolling-update-configuration
在厘清与金丝雀相关的各种概念定义之后,我们从设计者的角度思考金丝雀发布:如果让你设计一个金丝雀发布系统或者平台,你该如何实现?
笔者认为它至少要实现三个接口:
这三个接口与具体实现应该是无关的。比如你可以通过Prometheus实现指标的收集接口,也可以通过AWS的CloudWatch。
同时,金丝雀发布系统还需要一些用户体验性相关的功能,比如出现回滚时进行通知、滚动更新前进行人工审批、滚动更新的步骤大小等等。
金丝雀发布系统所需的接口后,我们发现,由于Service Mesh技术的兴起,让金丝雀发布的实现变得容易了很多。
因为Service Mesh技术天生就支持以上三个接口。所以,行业里一下就出现一些轻量级的发布系统,比如Argo Rollouts和Flagger。我们可以通过以下表格进行对比:
Flagger的三个接口的实现更丰富,几乎完胜Argo Rollouts。Argo Rollouts除了UI,几乎没有优势。
虽说金丝雀的好处是看得见的,但是并不代表,你的每一次发布都能使用它。我们需要清楚的认识到,执行金丝雀发布的过程中,程序存在一个中间状态:就是两个版本同时存在,有时甚至是多个版本。在生产环境,如果你的程序无法同时运行两个版本,你就不能采用金丝雀发布。这个风险需要开发在开发过程就确定的。
所以,我们认为采用金丝雀发布的前提是:开发人员开发出来的程序必须有同时运行多个版本的能力。
而这一能力,对程序员本身的能力也有要求。比如它要求程序员在设计接口和DB schema时考虑向前兼容。在程序员能力不足时,也无法采用金丝雀发布。
金丝雀发布的概念的理解程度,决定了团队是否能采用金丝雀发布,也决定了金丝雀发布系统的设计。
开源的金丝雀系统倾向于基于标准化的Kubernates平台,大概率是因为它更标准,更容易实现。而大多企业的金丝雀系统可能与企业内部系统耦合严重,无法开源。
微服务治理实践 | 金丝雀发布
本文是《微服务治理实践》系列篇的第三篇文章,主要分享 Spring Cloud & Dubbo 微服务框架下的金丝雀发布。
前言
这次改动的内容比较小,而且上线要求比较急,就不需要测试直接发布上线好了
发布不需要走灰度流程,快速发布上线即可
灰度发布没有什么用,就是一个流程而已,发布完就直接发布线上,不用等待观察
虽然灰度发布很重要,但是灰度环境很难搭建,耗时耗力优先级并不高
灰度发布策略
缺点: 成本较高,需要部署两套环境。如果新版本中基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户。
缺点: 没有覆盖到所有的用户导致出现问题不好排查
缺点: 发布和回滚周期较长
微服务金丝雀发布开源实现
-
Query Parameter 中存在 name=jim 的请求,路由到 192.168.1.1 节点
-
Header 中存在 Test=1 的请求,路由到 192.168.1.2 节点
-
Cookie 中存在 lang=zh-cn 的请求,路由到 192.168.1.3 节点
public class CanaryRouter extends AbstractRouter {
@Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
List<Invoker> normal = new ArrayList<>();
List<Invoker> canary = new ArrayList<>();
for(Invoker invoker : invokers) {
if(invoker.getUrl().getParameter("gray", false)) {
canary.add(invoker);
} else {
normal.add(invoker);
}
}
if(invocation.getMethodName().equals("getEnv")) {
return canary;
} else {
return normal;
}
}
}
-
版本: Apache Dubbo 支持 2.5.x, 2.6.x 以及 2.7.x;Spring Cloud 支持 Dalston、Edgware、Finchley 以及 Hoxton(暂不支持 Hoxton 里的 Spring Cloud LoadBalancer 负载均衡组件)
-
注册中心: 支持 Zookeeper,Consul,Eureka,Nacos,Etcd 等注册中心
金丝雀发布
金丝雀发布结果验证
Spring Cloud
-
按比例灰度,可设置 0 - 100 之间的整数
-
按内容灰度,可以根据参数的内容进行灰度
URL: http://custom-provider/goods/query
Parameter: goodsId=JL110
Header: ENV=Prod
-
按比例灰度,可设置 0 - 100 之间的整数
-
按内容灰度,可以根据接口参数的内容进行灰度
public interface CanaryService {
String call(String str, int num1,
Integer num2, String[] strArr, Map<String, String> map,
List<String> list, User user);
}
str=str
num1=1
num2=2
strArr=[1, 2, 3]
map={"1":"1", "2", "3"}
list=[0, 1, 2]
User=User{name=name, age=20}
参数 3 表示一个 String[] 数组,表达式 [0] 表示取第 1 个元素,数组中的第 1 个元素为 1。
参数 4 表示一个 Map<String, String>,表达式 .get("1") 表示取 key 为 "1" 的元素,Map 中 key 为 "1" 的元素是 "1"。
参数 5 表示一个 List 集合,表达式 .get(1)表示取第 2 个元素,数组中的第 2 个元素为 1。
参数 6 表示一个自定义 User 对象(有 name 和 age 两个属性),表达式 .getName() 表示调用 getName() 方法,该方法返回 name 属性的值,这里传递的是 name。
金丝雀发布实现细节
Apache Dubbo 金丝雀底层实现的原理是通过 Java Agent 技术动态添加一个 Router,该 Router 内部使用了 Spring 的表达式 SPEL 进行参数,表达式解析结果判断是否需要对 Invoker 列表进行修改。如果是常规请求,删除灰度节点;如果是灰度请求,删除正常节点。
招贤纳士
Java干货
视频资料
技术交流群
以上是关于金丝雀发布的本质的主要内容,如果未能解决你的问题,请参考以下文章