跳到主要内容

金丝雀群组:按 ID 哈希的分流如何将核心用户聚集到同一实验组

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个发布团队在百分比旗标(percentage flag)的保护下发布了一个新模型。分桶计算公式为 hash(user_id) % 100,金丝雀(canary)测试覆盖 0–4 桶。在两周内,人均参与度的提升显著且稳定,于是团队将比例提升到 20%,随后是 50%,最后推向全球。在 50% 到全量发布的某个阶段,这种提升突然消失了。事后复盘(post-mortem)发现问题出在金丝雀人群(canary cohort)。实验变量并没有真正改变指标。金丝雀组的样本是一个特殊的群体。

团队以为自己是在对用户进行采样,实际上它是在对 ID 进行采样。

这两个词看起来可以互换,直到你意识到 ID 并非由用户生成。它们是由账户创建当天运行的任何系统生成的——可能是 Postgres 中的序列,或者是 Snowflake 风格的时间编码整数,或者是带有时间戳前缀的 UUIDv7。如果该生成器嵌入了时间,那么“ID 相邻的用户”实际上意味着“在同一时间段注册的用户”。而注册时间是大多数产品中衡量行为最强的预测因子之一。两年前引入一波核心用户潮的病毒式集成,占据了 ID 空间中为期六个月的时间窗口。任何不主动打乱该窗口的分桶方案,都可能将这批用户完整地划分到同一个实验组中。

哈希函数完全是在执行你的指令

残酷的是,哈希函数是无辜的。在稠密的 ID 空间上,一个优秀的哈希函数会产生 ID 的均匀分布。如果你检查分桶分配的边际分布,每个桶的数量大致相同,样本比率失配(SRM)的卡方检验结果正常,实验平台也会宣布流量分配是健康的。SRM 检查是检测分配链路是否损坏的正确工具——例如缺失的变体脚本、导致一半变体丢失的重定向、或者失效的定向规则——但它们比较的是每个桶的用户数量,而不是构成。数量相等但构成不等,是标准健康检查在设计上就会忽略的一类偏差。

哈希函数在不同实验中还会重复使用相同的摘要。如果两个并行实验使用了相同的盐值(salt)或相同的分区策略,产生的分配在单个实验中看起来是独立的,但在合并分析时会显示出相关性——这是一种已知的故障模式,通常在平台团队寻找虚假提升(phantom lifts)的来源时浮出水面。这种情况下的解决方法是为每个实验设置独立的盐值。而此案例中的解决方法则不同,因为问题不在于实验之间的冲突,而在于 ID 空间与人群空间(cohort space)之间的冲突。

为什么“ID 均匀”不等同于“用户均匀”

哈希分桶方案提供了一个隐含的契约:如果我对唯一标识符进行哈希,我就能得到一个可交换的用户样本。只有当标识符与你关心的变量在统计上相互独立时,这一约定才成立。对于一个没有信息内容的随机分配标识符,这是成立的。但对于一个随注册时间单调递增的整数,它就不成立了——标识符携带了时间协变量,任何与注册时间相关的群体行为都会渗透到分桶分配中。

最常见的版本是核心用户偏差(heavy-user bias)。微软研究院的论文《关于 A/B 测试中的核心用户偏差》(On Heavy-user Bias in A/B Testing)指出,通常只有极小比例的账户驱动了大部分指标的变化,而实验窗口内的核心用户构成可能与长期总体分布存在显著偏差。当核心用户在特定维度(注册时间窗、地理位置、订阅层级、设备)上聚集,且你的分桶函数对该维度敏感时,实验测量的就是与最终全量发布时不同的群体。这种偏差并不是因为实验运行时间太短产生的,而是由于分配方式在基于数量的健康检查无法察觉的情况下,呈现出非随机性。

注册时间人群是一个教科书般的案例。核心用户往往在特定时期集中注册:一次发布、一个媒体周期、一次病毒式集成或一次合作伙伴活动。这些爆发产生了密集的 ID 范围。一个将相邻 ID 映射到相邻分桶的哈希函数——许多实际应用中的哈希函数都是如此,特别是在分桶数量较少时的取模(modulo)或折叠混合(fold-and-mix)变体——会将连续的 ID 范围路由到连续的分桶范围。一个映射到 0–4 桶的 5% 金丝雀测试包含五个连续的分桶边界。从理论上讲,一个参与度极高的六个月注册窗口完全有可能全部落在执行这五个桶中。从概率上讲,平均而言这似乎不太可能发生,但“核心用户人群落在哪”在少量分桶中的方差足够大,以至于任何一次发布都可能撞上这种糟糕的安排。

标准健康检查漏掉了什么

当实验组的数量与预期百分比偏差过大时,实验平台的 SRM 检测器就会报警。该检查可以捕捉到带有热点的哈希函数、在部分变体页面失效的跟踪脚本或导致流量丢失的重定向。但它无法捕捉到数量平衡的分组——即其中一个实验组的用户上个月在产品上的支出恰好是另一个组的 5 倍。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates