金丝雀 — 比权重更重要的是中止条件
一句话总结
金丝雀不是“给新版本一点流量”,而是**“先确定某个指标什么时候会停止并倒退,然后再给一点流量”**。
为什么需要这个?
光是滚动更新,帕德就会一点一点地更换。但是滚动更新所看到的只有帕德的健康状态。如果过程还在运行,readyness probe通过的话,就会继续滚动。如果新版本能很好地输出200,但响应内容有误,p99延迟增加了三倍,或者只有在特定请求时才能输出500,滚动更新就会什么都没注意就一直走下去。
Messy的流量分组在这里加上一个杠杆。是将板块数量和流量比例分离。即使提前全部启动v2板块,流量也只能减少0%,如果出现问题,可以不触动板块,只将权重恢复为0。不需要在回滚时进行部署,这就是与滚动更新之间的决定性区别。
怎么行动
加权分组被翻译为Envoy的WeightedCluster。每次请求都会抽取随机数,根据加权范围选择聚类。所以**不是确切的90:10,而是概率上接近90:10。**如果请求只有100个,12个可能会变成v2,因为这种特性,在流量较少的服务中,要等到每个金丝雀阶段积累足够的样本才能判断有意义。
加权数的和必须是必须是100。如果和不一致,会在验证阶段被拒绝,多亏了这个规则,结构上阻止了“把v1降低到90,但忘记提高v2”的思维。
分拆方式要区分三种使用。
| 方式 | 对象 | 使用时 |
|---|---|---|
| 加权 | 随机部分用户 | 一般渐进式部署 |
| 标题匹配 | 仅限指定人员 | 内部测试人员先行公开,QA |
| 映象 | 没有人(仅副本) | 负载·回归验证为用户影响0 |
镜像(阴影化)特别容易产生误解。**请求副本的响应将被完全丢弃。即使镜像对象已死亡,也不会影响用户的响应。相反,镜像请求也会真正引起DB写入或外部API调用等副作用。要镜像写入路径,必须在应用程序层准备好使新版本以影子模式运行。镜像请求的Host头包含-shadow因为有后缀,所以可以在日志中区分,并且必须区分。
加权分拆还有一个陷阱。**因为每次请求都会抽取随机数,所以同一用户每次浏览屏幕时都会来回切换v1和v2。**如果会话状态或UI在每个版本上不同,这看起来就是一个错误。解决方法是DestinationRule的一致哈希加载平衡。特定头文件(例如:x-user-id)进行哈希,相同的密钥总是发送到相同的端点。由于是哈希环结构,即使端点增加或减少,重新映射也最少。
最后,金丝雀计划必须是可执行的定义,而不是文件。每个步骤都必须有(1)权重、(2)判断是否进入下一个步骤的标准、(3)观察时间,并且整个流程必须有回溯方法。Flagger或Argo Rollouts将这个定义作为CRD接收,自动运行。自动化的真正价值不是速度,而是消除即使看到坏指标也犹豫不决的人性偏见。
在现场相遇的样子
**第一,标签不一致无法开始的金丝雀。**如果subset指定的标签上没有一个pad,那么通过该subset的流量全部为503(UH)。提高权重到10的瞬间,请求的10%就会死亡。这就是为什么在部署管道中加入验证subset标签和pad标签一致性的步骤的团队很多的原因。
第二,没有门的金丝雀。 10 → 30 → 50 → 100 通过人眼观察上升的方式,虽然作为起点是可以的,但夜间分发很难,判断会摇摆不定。如果无法将错误率和延迟临界值固定在阶段定义中,那么判断就会从人那里转移。
**第三,没有回头的金丝雀。**如果已经删除了v1,即使把权重调到0也没有地方去。金丝雀结束到100%为止,之前的版本必须活着,那个整理的时间点也必须在计划中。
下次实习要做的事情
从100/0开始转到90/10,确认合计不是100的情况下,Manifest如何被拒绝。依次添加作为头部的仅发送给内部测试者的新版本的路由、丢弃响应的映象,以及固定同一用户在一个版本上的一致哈希。最后,创建包含步骤、判断标准、回滚的Canary计划文件,并将实际消息推进到50/50中间阶段。
有一个需要注意的地方。这个练习的前阶段不是评级集群,而是评级存储的文件。vs-baseline.yaml,vs-90-10.yaml,vs-header.yaml,vs-mirror.yaml应该单独保留每个阶段的快照。如果一直修改一个文件,前一个阶段的基础就会消失。在实际工作中,分别提交每个金丝雀阶段的宣言也是正统的做法——因为在哪个阶段发生了什么变化,很快就会成为事故调查资料。