灰度发布的难点不在「推送新配置」,而在「只让一部分实例用新版本、并且随时能撤」。这篇用 200 个实例做按比例放量、按实例白名单、一键回滚和错误触发的自动回滚,每一步量实际生效的实例数与耗时。
percent= 0: 0 / 200 个实例在用新版本(0.0%);收敛耗时 96.2 ms percent= 5: 7 / 200 个实例在用新版本(3.5%);收敛耗时 137.5 ms percent= 20: 38 / 200 个实例在用新版本(19.0%);收敛耗时 143.7 ms percent= 50: 94 / 200 个实例在用新版本(47.0%);收敛耗时 138.7 ms percent=100:200 / 200 个实例在用新版本(100.0%);收敛耗时 143.4 ms 放量是单调的(5% 时的实例,20% 时仍在新版本里;20% ⊂ 50% ⊂ 100%):True
灰度判断在客户端(实例自己)做:服务端只存一个 percent 数字,所有实例用同一个哈希函数算自己的桶。这样配置中心几乎没有压力,但意味着每个客户端都要带这段逻辑。推送机制见配置中心。
用哈希而不是随机数,放量才是单调的。如果每次放量都重新随机,就会有实例在新旧版本间来回切换。
percent=0 后 0 个实例仍在新版本;最后一个实例切回旧版本 83.9 ms 之后
回滚就是把 percent 写回 0。因为所有实例都在 watch 同一个节点,所以回滚和放量一样快。
percent=0,在用新版本的实例:['inst-003', 'inst-077', 'inst-150'] 删除白名单节点后,在用新版本的实例数 = 0
放量到 20%:38 个实例在用新版本;它们之中有 8 个开始出错 控制者在看到 5 个错误节点时(阈值 5)回滚;从第一个错误上报到所有实例回到旧版本共 95 ms;仍在用新版本的实例 = 0
实例上报错误用的是临时节点:实例死亡、会话过期后错误记录会自己消失。这里的阈值逻辑非常简化。