灰度只放少量流量时,例外往往被平均数据掩盖;真正的问题不是灰度本身,而是你用来判断放量的那个条件是否覆盖了全量场景。把灰度当成一次可回滚的发布,而不是一次抽样统计,才能让例外在扩大范围前现形。
同样是“放 5% 流量”,两种做法会得到完全不同的结论。按请求比例放量,命中的是随机访问者,适合验证服务端响应、缓存命中、连接复用这类与具体页面无关的指标;按页面或目录放量,命中的是一组确定的 URL,适合验证模板渲染、跳转规则、静态资源路径这类与内容结构绑定的问题。
如果你要观察的是“某个栏目改版后会不会出现例外”,就必须按 URL 集合放量,而不是按请求比例。否则同一篇内容可能被新旧两套模板交替渲染,你看到的差异来自随机命中,而不是发布本身。判断依据很简单:灰度期间对同一 URL 连续请求多次,如果返回内容不稳定,说明放量维度选错了,下一步应先固定维度再继续。
把你要放量的对象落成一份清单,是让例外可被复查的前提。清单不需要很长,但每一项都要能对应到一个可验证的结果。假设你手里有 40 个页面,可以这样分组:
清单的作用不是穷举,而是让“例外”有归属。灰度阶段如果某个分组全部正常,而另一个分组出现异常,你就能把放量范围限定在正常分组,而不是整体推进或整体回退。这个动作直接决定下一步是扩大范围还是先修某一类页面。
小流量阶段最容易漏掉的是低频路径。它们在全量下占比很小,在灰度里可能一次都没被命中。常见的例外有三类,你可以对照自己的清单判断属于哪一类:
区分它们的方法不是看错误率,而是看错误是否集中在某一类 URL 或某一个参数上。如果异常只出现在带特定参数的页面上,更可能是条件分支问题;如果同一 URL 在不同时间返回不同结果,更可能是缓存分层问题。这个判断会影响你下一步是改模板、清缓存,还是核对依赖配置。
灰度通过不等于可以全量,这是两种做法的分界点。选择继续放量的条件应当是:清单中每个分组都至少被命中过一次,且同一 URL 多次请求结果一致。如果某个分组始终没有被命中,你得到的只是“未验证”,不是“正常”。
选择先补齐命中再放量,代价是发布周期变长;选择直接放量,代价是例外可能在更大范围内同时出现,回滚成本更高。两者都成立,区别在于你是否能承受一次全量回滚。如果回滚涉及缓存刷新或数据写入,代价通常高于多等一轮灰度。
这里有一个容易忽略的事实:抓取限制和收录状态不能互相替代。用 robots.txt 限制抓取,并不等于页面会从索引中消失;提交站点地图也不保证被抓取或收录。灰度期间如果发现某些页面没有被外部访问过,不能据此判断它们“没问题”,只能说明它们还没有被验证过。
灰度结束后,无论是否放量,都应留下一条可复查的记录:哪些分组被命中、哪些未被命中、异常集中在哪一类 URL。下一次发布时,这份记录可以直接变成新一轮灰度的清单起点。
如果这次灰度暴露的例外属于条件分支未覆盖,下一步应把缺失的参数组合补进清单,而不是调整放量比例;如果属于缓存分层不一致,下一步应先确认刷新机制再放量。把例外归到具体类别,才能让下一次灰度真正缩小不确定性,而不是重复同一个盲区。