投放引擎 (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 实验数据: 实验分流和指标计算
- 预算消耗数据: 实时预算消耗的计算和同步
- 频控数据: 用户频次数据的实时更新和查询
- 监控数据: 各环节延迟、成功率、异常监控
面试高频问题
- 广告投放引擎的核心流程是什么?
- 召回阶段有哪些常见策略?
- eCPM 排序公式是什么?各因子的含义?
- 预算控制 (Pacing) 是如何实现的?
- 新广告冷启动问题如何解决?
- 广告系统如何做到 100ms 内响应?
推荐阅读