跳转至

投放引擎 (Ad Serving)

一句话概述

投放引擎是广告系统的核心,负责在毫秒级内从海量广告中选出最优广告展示给用户,核心流程为"召回→粗排→精排→重排→竞价→展示"。


投放引擎整体架构

flowchart LR
    A[用户请求] --> B[流量接入<br/>Router]
    B --> C[广告召回<br/>Retrieval]
    C --> D[排序层<br/>Ranking]
    D --> E[机制层<br/>Mechanism]
    E --> F[广告响应]

    B -.- B1[请求解析<br/>用户识别<br/>特征获取]
    C -.- C1[候选广告集<br/>定向匹配<br/>粗排过滤]
    D -.- D1[pCTR/pCVR<br/>质量分<br/>精排/重排]
    E -.- E1[竞价/预算<br/>频控/去重<br/>计费]

核心流程详解

Step 1: 请求接入与解析

输入: 原始广告请求
输出: 结构化请求 + 用户特征

处理内容:
1. 协议解析 (HTTP/gRPC → 内部结构体)
2. 参数校验 (广告位ID、设备信息等)
3. 用户识别 (DeviceID → UserID, ID Mapping)
4. 实时特征获取 (从 Feature Store 拉取用户特征)
5. 上下文特征提取 (时间、地域、网络、设备)

Step 2: 广告召回 (Ad Retrieval)

输入: 用户特征 + 广告位信息
输出: 候选广告集 (通常 100–1000 个)

目标: 从全量广告库 (百万级) 中快速筛选出可能相关的候选集

召回策略

策略 说明 特点
定向召回 基于广告主设定的定向条件 最基础,必须满足
倒排索引 按定向标签建立倒排索引 高效,O(1) 查找
向量召回 用户/广告 Embedding 相似度 泛化能力强
行为召回 基于用户历史行为 个性化强
热门召回 高 CTR/高消耗广告 兜底策略
Lookalike 召回 相似人群扩展 扩量

定向匹配 (Targeting Match)

广告计划定向条件:
  - 地域: 上海、北京
  - 年龄: 25-35
  - 性别: 女
  - 兴趣: 美妆、护肤
  - 设备: iOS

用户属性:
  - 地域: 上海 ✓
  - 年龄: 28 ✓
  - 性别: 女 ✓
  - 兴趣: [美妆, 旅游, 美食] ✓ (命中美妆)
  - 设备: iPhone 14 ✓

结果: 匹配通过,进入候选集

Step 3: 粗排 (Pre-Ranking)

输入: 候选广告集 (100–1000 个)
输出: 粗排后候选集 (50–200 个)

目标: 用轻量模型快速过滤明显不相关的广告
  • 模型: 轻量级模型 (LR, 小型 NN)
  • 特征: 少量核心特征
  • 延迟: < 5ms
  • 作用: 减少精排的计算量

Step 4: 精排 (Ranking)

输入: 粗排后候选集 (50–200 个)
输出: 带预估分数的排序列表

目标: 精确预估每个广告的 pCTR、pCVR,计算 eCPM
  • 模型: 复杂深度模型 (DeepFM, DIN, DIEN 等)
  • 特征: 全量特征 (用户+广告+上下文+交叉)
  • 延迟: < 20ms
  • 核心输出: pCTR, pCVR, 质量分

eCPM 排序公式

eCPM = f(bid, pCTR, pCVR, quality_score)

常见形式:
  效果广告: eCPM = bid × pCTR × pCVR × 1000
  品牌广告: eCPM = CPM_bid × quality_score
  搜索广告: eCPM = CPC_bid × pCTR × quality_score × 1000

Step 5: 重排 (Re-Ranking)

输入: 精排后的 Top-N 广告
输出: 最终展示列表

目标: 在精排基础上加入全局优化策略
  • 多样性: 避免同类广告扎堆
  • 上下文感知: 考虑已展示广告的影响
  • 探索与利用: 给新广告一定曝光机会
  • 广告主均衡: 避免单一广告主垄断

Step 6: 机制层 (Mechanism)

竞价 → 预算控制 → 频次控制 → 计费

竞价机制

GSP (Generalized Second-Price)

搜索广告中多个广告位的竞价:

广告位 1 (最优位置):
  广告A: eCPM = ¥100 → 胜出,支付 ¥80.01 (B的eCPM + ¥0.01)
广告位 2:
  广告B: eCPM = ¥80  → 胜出,支付 ¥50.01
广告位 3:
  广告C: eCPM = ¥50  → 胜出,支付底价

挤压效应 (Squashing)

原始排序: eCPM = bid × pCTR × pCVR
问题: 高 pCTR 的广告总是排在前面,新广告难以获得曝光

解决: eCPM = bid × pCTR^α × pCVR^β  (α, β < 1)
通过指数压缩,降低预估值的影响,给更多广告机会

预算控制 (Budget & Pacing)

为什么需要预算控制?

  • 广告主设定日预算 ¥10,000
  • 如果不控制,可能上午就花完了
  • 需要让预算均匀消耗,覆盖全天流量

Pacing 策略

匀速消耗 (Smooth Pacing)

目标: 预算在投放时段内均匀消耗

方法:
  理想消耗 = 日预算 × (已过时间 / 总投放时间)
  实际消耗 vs 理想消耗 → 调整出价系数

  消耗过快 → 降低出价系数 (throttle)
  消耗过慢 → 提高出价系数 (boost)

PID 控制

error = 目标消耗速率 - 实际消耗速率
adjustment = Kp × error + Ki × ∫error + Kd × d(error)/dt

Kp: 比例系数 (响应当前误差)
Ki: 积分系数 (消除累积误差)
Kd: 微分系数 (预测未来趋势)

概率过滤 (Probabilistic Throttling)

以概率 p 参与竞价:
  p = min(1, 剩余预算 / 预估剩余消耗)

优点: 实现简单,效果稳定
缺点: 可能错过高价值流量

多计划预算分配

广告主总预算: ¥100,000/天
  ├── 计划A (核心人群): ¥50,000
  ├── 计划B (扩量人群): ¥30,000
  └── 计划C (测试人群): ¥20,000

动态调整: 根据各计划 ROI 实时调整分配比例

频次控制 (Frequency Capping)

为什么需要频次控制?

  • 同一用户反复看到同一广告 → 体验差、效果递减
  • 需要限制每个用户看到同一广告的次数

控制维度

维度 示例
广告级别 每个用户每天最多看到广告A 3次
广告主级别 每个用户每天最多看到品牌X的广告 5次
行业级别 每个用户每天最多看到游戏广告 10次
时间窗口 每小时/每天/每周

技术实现

方案1: Redis 计数器
  Key: freq:{user_id}:{ad_id}:{date}
  Value: 展示次数
  TTL: 24h

方案2: Bloom Filter (近似)
  适用于海量用户的近似频控
  允许少量误判

方案3: 本地缓存 + 异步同步
  请求处理时查本地缓存
  异步更新到中心存储

广告质量控制

质量分 (Quality Score)

Quality Score = f(历史CTR, 落地页质量, 广告相关性, 用户反馈)

作用:
  - 影响 eCPM 排序
  - 质量分高的广告可以用更低出价获得展示
  - 激励广告主提升广告质量

负反馈机制

用户行为信号:
  - 点击"不感兴趣" → 强负反馈
  - 快速滑过 → 弱负反馈
  - 长时间停留 → 正反馈
  - 点击后快速返回 → 负反馈

处理:
  - 实时降低该广告/广告主的排序分
  - 更新用户兴趣模型
  - 严重负反馈 → 屏蔽该广告

冷启动问题

新广告冷启动

问题: 新广告没有历史数据,pCTR/pCVR 预估不准
影响: 新广告难以获得曝光 → 无法积累数据 → 恶性循环

解决方案:
1. 探索流量池: 分配一定比例流量给新广告
2. 相似广告迁移: 用相似广告的历史数据初始化
3. 特征泛化: 使用广告主/行业级别特征代替广告级别特征
4. 乐观初始化: 给新广告较高的初始预估值
5. Thompson Sampling: 基于贝叶斯的探索策略

新用户冷启动

问题: 新用户没有行为数据,无法精准定向

解决方案:
1. 基于设备/地域/时段的粗粒度特征
2. 热门广告兜底
3. 快速学习: 根据前几次交互快速更新用户画像

性能优化

延迟优化

手段 说明
多级缓存 本地缓存 → Redis → DB
并行处理 召回、特征获取并行执行
预计算 离线预计算部分特征和分数
模型裁剪 量化、剪枝、蒸馏
批量推理 GPU 批量处理多个广告的预估
超时控制 各环节严格超时,降级策略

典型延迟分布

总延迟目标: < 100ms (端到端)

请求解析:     ~2ms
特征获取:     ~10ms (并行)
广告召回:     ~10ms
粗排:         ~5ms
精排:         ~15ms (GPU 推理)
重排+机制:    ~5ms
响应序列化:   ~3ms
────────────────────
总计:         ~50ms (服务端)
网络传输:     ~20-30ms
客户端渲染:   ~20-30ms

与大数据开发的关联

  • 特征数据管道: 实时/离线特征的计算和存储
  • 日志采集: 请求/召回/排序/展示/点击全链路日志
  • 样本生成: 从日志中提取训练样本
  • A/B 实验数据: 实验分流和指标计算
  • 预算消耗数据: 实时预算消耗的计算和同步
  • 频控数据: 用户频次数据的实时更新和查询
  • 监控数据: 各环节延迟、成功率、异常监控

面试高频问题

  1. 广告投放引擎的核心流程是什么?
  2. 召回阶段有哪些常见策略?
  3. eCPM 排序公式是什么?各因子的含义?
  4. 预算控制 (Pacing) 是如何实现的?
  5. 新广告冷启动问题如何解决?
  6. 广告系统如何做到 100ms 内响应?

推荐阅读