2. 分流原理与流量分配

分流(Traffic Split)是 Champion Challenger 实验的基石。其核心目标是将用户流量按照既定规则划分到不同实验组(Champion 组、Challenger 组),确保各组在统计意义上具有可比性,从而让后续的指标对比归因于策略差异而非流量偏差。

2.1 分流的基本概念

分流本质上是一个映射函数:给定一个用户标识(如 user_id、device_id)和实验配置,输出该用户应进入的实验组编号。一个标准的分流系统包含以下要素:

  • 实验层(Layer):一个独立的流量划分空间,不同层之间流量正交。
  • 实验组(Bucket/Variant):同一层内的不同策略版本,如 Control(Champion)和 Treatment(Challenger)。
  • 分流单元(Unit):被分配的最小实体,通常为用户 ID 或会话 ID。
  • 流量比例(Traffic Ratio):每组应占的流量百分比,总和为 100%。
关键原则:分流必须是确定性的——同一用户在相同实验配置下,每次请求都应被分入同一组。这保证了用户体验的一致性,避免用户在不同组间反复横跳。

2.2 流量切分策略

根据业务场景和技术选型,常见的流量切分策略有三种:随机分流、哈希分流和分层分流。下表对比了它们的核心差异:

策略 原理 优点 缺点 适用场景
随机分流 使用伪随机数生成器(PRNG)对用户 ID 取模或生成随机值 实现简单,无需复杂哈希函数 无法保证跨实验的一致性;用户量少时易产生偏倚 小规模、非关键实验;快速原型验证
哈希分流 对用户 ID 进行哈希运算(如 MD5、MurmurHash),取哈希值的模 确定性高;分布均匀;支持一致性哈希 需要选择好的哈希算法;哈希碰撞需处理 大规模生产环境;需要稳定分流的长期实验
分层分流 将流量划分为多个独立层,每层可独立分配比例,层间正交 支持多实验并行;流量复用率高;避免交互干扰 架构复杂;需要维护层映射表 大型平台同时运行数十个实验

2.3 哈希分流详解

哈希分流是生产环境中最常用的策略。其工作流程如下:

  1. 输入:用户标识(如 user_id = "user_12345")和实验层标识(如 layer = "recommend_v2")。
  2. 拼接:将用户标识与层标识拼接成字符串,如 "user_12345:recommend_v2"。
  3. 哈希:使用 MurmurHash3 或 MD5 计算拼接字符串的哈希值,得到一个 32 位或 128 位的整数。
  4. 取模:将哈希值对 100 取模(或对 10000 取模以获得更高精度),得到 0–99 之间的整数。
  5. 映射:根据预配置的流量比例,将模值映射到具体实验组。
实践建议:推荐使用 MurmurHash3 或 xxHash 等非加密哈希算法,它们速度快、分布均匀。避免使用 MD5 或 SHA 系列,虽然安全但性能较差,不适合高并发分流场景。

以下是一个 Python 风格的哈希分流伪代码示例:

import hashlib

def assign_bucket(user_id, layer, buckets):
    """
    user_id: 用户标识字符串
    layer: 实验层名称
    buckets: 列表,每个元素为 (bucket_name, ratio),ratio 为百分比整数
    """
    raw = f"{user_id}:{layer}"
    hash_val = int(hashlib.md5(raw.encode()).hexdigest(), 16)
    mod_val = hash_val % 100

    cumulative = 0
    for name, ratio in buckets:
        cumulative += ratio
        if mod_val < cumulative:
            return name
    return buckets[-1][0]  # 兜底返回最后一组

2.4 分层分流架构

当平台同时运行多个实验时,分层分流可以避免流量冲突。其核心思想是:将全部流量视为一个整体,通过层(Layer)进行逻辑隔离。每个层拥有独立的哈希空间,用户在不同层之间被独立分配,从而实现正交性。

下图展示了分层分流的基本架构:

分层分流架构示意图 100% 总流量 流量分配器 Layer A: 推荐实验 Layer B: 搜索实验 Layer C: 定价实验 Champion (50%) Challenger (50%) Champion (70%) Challenger (30%) Champion (80%) Challenger (20%) 正交性说明 同一用户可同时处于 Layer A 的 Champion 组、Layer B 的 Challenger 组 和 Layer C 的 Champion 组,各层分配互不影响。

2.5 流量比例配置

流量比例的配置直接影响实验的统计功效和风险控制。常见的配置模式包括:

  • 50/50 均分:Champion 和 Challenger 各占 50%。适用于风险较低、需要快速得出结论的实验。
  • 90/10 小流量:Champion 占 90%,Challenger 占 10%。适用于高风险策略,先在小范围验证效果。
  • 多组并行:如 Champion 50%、Challenger A 25%、Challenger B 25%。适用于同时测试多个候选策略。
  • 动态调整:实验进行中根据中间指标(如负向指标监控)动态调整比例,需配合流量调度系统。
避坑提示:不要将流量比例配置为极端值(如 99.9% vs 0.1%)。极小的实验组样本量会导致统计检验失效,且无法排除随机波动。建议最小实验组流量不低于总流量的 1%,且绝对样本量满足最小样本量要求。

以下是一个流量比例配置的 JSON 示例,展示了多组并行配置:

{
  "experiment_id": "rec_algorithm_v3",
  "layer": "recommendation",
  "hash_algorithm": "murmur3_32",
  "buckets": [
    {"name": "champion", "ratio": 50, "description": "当前线上算法"},
    {"name": "challenger_a", "ratio": 25, "description": "新模型 v1"},
    {"name": "challenger_b", "ratio": 25, "description": "新模型 v2"}
  ],
  "fallback": "champion"
}

2.6 分流一致性保障

分流一致性是实验可信度的生命线。以下是保障一致性的关键措施:

措施 说明 实现方式
确定性哈希 同一用户始终映射到同一组 使用用户 ID + 层 ID 作为哈希输入
缓存分流结果 避免重复计算导致不一致 Redis 或本地缓存存储 user_id → bucket 映射
版本化配置 实验配置变更时保留历史版本 配置中心存储带版本号的分流规则
一致性哈希环 当实验组数量变化时最小化重分配 使用一致性哈希算法替代简单取模
工程实践:在微服务架构中,建议将分流逻辑封装为独立的 SDK 或 Sidecar 组件,所有服务通过同一套分流库计算分组,避免各服务独立实现导致的分流不一致问题。