AdTechSep 11, 2026阅读需 10 分钟

竞价请求内的 ML 推理:特征拉取、批处理与降级时的出价

实时竞价ML 推理CTR 预估长尾延迟
图片加载失败

一个必须在每个竞价请求之内作答的 CTR 或转化模型,错过时限的地方通常有两处,却被归在同一个名字底下:从远端存储迟到的特征,以及在队列里等待的求值。本文讲竞价时限怎么拆分、哪些运行时和批处理选择适合按请求计算的预算、模型迟到时出价方怎么做,以及如何分辨哪些工程公司真正在做这类工作。

在出价路径内给点击概率和转化概率打分的模型,是由一只不属于它的时钟来评判的。广告交易平台到了时限就不再接收,在那一刻之后才落地的预测不是一个慢了的回答:它根本不是回答,而算力已经花出去了。

这个需求通常以推理延迟目标的形式出现。把它当成一道减法更好用:竞价时限扣掉网络、请求解析和特征查询之后还剩多少,以及什么都不剩时出价方出什么价。

简短的答案是结构性的。先拆分时限,再选模型:请求到达时打上一个绝对时限,特征拉取用完自己的份额就取消,在出价方进程内求值、前面不设队列,并让降级阶梯以一个干净的 no-bid 收尾。amBrain 可以公开证实的内容:我们构建了 RTBBidder,一个需求方平台。本文描述的是请求内推理的机理,不是我们的某个案例,下文没有任何一个数字是在我们自己的系统上测得的。

时限随请求一起到达,推理拿到的是剩下的部分

在 OpenRTB 2.6 中,tmax 是广告交易平台允许收到出价的最长毫秒数,其中包含互联网延迟,并且它优先于广告交易平台事先给出的任何指引。这个预算不是你服务的一个配置项:它随每个请求一起传递。

Google Authorized Buyers 于 2026 年 8 月更新的文档说,BidRequest.tmax 中的时限通常在 80 到 1000 ms 之间,既覆盖到交易所在地的网络时间,也覆盖你的出价方生成响应所需的时间。它要求从交易所在地看,85% 的响应落在时限之内,并对无法稳定做到这一点的出价方限流。

所以时限是一个总和,模型只占其中一项:

  • 到广告交易平台的往返:在模型上做多少工作都缩短不了
  • 解析请求,并通过定向、预算和频次过滤器筛选候选
  • 针对用户和上下文的特征拉取,通常是一次自带长尾的网络调用
  • 对筛选后留下的候选求值,然后定价并编码响应
  • 为以上各项的波动预留的余量,要从你自己按广告交易平台拆分的直方图里读出,而不是从平均值里读

请求到达时,根据 tmax 减去你为该广告交易平台实测的网络链路耗时,打上一个绝对时限,并把剩余时间而不是固定超时传给每个阶段。gRPC 文档描述的是同一个机制:向下传播的时限会变成一个已经扣除流逝时间的超时,而服务端应用仍要负责停止它派生出去的工作。

剩余时间不够打分时,就尽早作答。OpenRTB 2.6 给出两种 no-bid 形式:带 HTTP 204 的空响应,或在 nbr 中带原因码的出价响应,并且它鼓励使用原因码。迟到的回答代价更高:Google 的 callout 配额系统会向未能及时响应的出价方发送更少的 callout,并在几分钟内做出调整。

特征拉取和模型求值的失败方式不同,所以各给各的预算

「推理」这个词底下藏着两个阶段。特征拉取是输入输出:来自远端存储的历史、频次和上下文信号,它的长尾属于网络和那个存储。求值是计算:一次前向传播或一次对树的遍历,它的长尾属于你自己进程内部的 CPU 争用。

把两者混在一起的 p99,说明不了该修哪一个,所以每个广告交易平台要维护两个直方图,并按特征存放的位置给特征分类:

  • 请求特征:直接从竞价请求本身读取,零成本,也是唯一不可能迟到的一类
  • 广告活动与创意特征:放在进程内存里,在热路径之外重建,所以重建慢了损失的是新鲜度,而不是一次出价
  • 来自远端存储的用户与历史特征:长尾最大,预算紧张时第一个被砍的就是这一组
  • 按请求计算的交叉特征:其成本随候选数量增长

带时限的拉取,需要一个预料到答案会缺失的模型:训练时让一部分样本缺少那组迟到的特征,或者另外保留一个不含这组特征的模型,这样被取消的查询对预测的影响,就是你测量过的。

Dean 与 Barroso 在 2013 年的 The Tail at Scale 中描述了对冲请求:短暂延迟之后,向另一个副本再发一份同样的请求,采用先到达的那个回答。在他们的 BigTable 基准测试中,10 ms 后发出的对冲请求把读取 1,000 个值的第 99.9 分位延迟从 1,800 ms 降到了 74 ms,同时多发了 2% 的请求。在竞价之内,对冲延迟必须从拉取剩余的份额里出。

按能否不经网络跳转、直接在你的进程内运行来选模型格式

选运行时,主要是在决定在哪里求值。独立的推理服务器会给每个要打分的请求加上一次往返和一个队列;在出价方进程内部求值,两样都不加,取而代之的是把它的内存和线程交到你手上。四种常见选择:

  • 基于稀疏特征的逻辑回归,也就是对激活权重求和:McMahan 等人在 KDD 2013 上为 Google 广告点击预测描述的单层模型
  • 预先编译的树集成模型:dmlc 项目的 TL2cgen 把随机森林和梯度提升模型转换成 C 代码,以原生二进制形式分发
  • 在 ONNX Runtime 中运行的小型神经网络:它的 intra-op 线程池默认每个物理核一个线程,并开启自旋;如果处理函数已经占满了每个核,就按请求而不是按机器来设定线程池大小
  • 独立的服务器,如 Triton 或 TensorFlow Serving:当模型需要加速器或自己独立的发布周期时

量化是 CPU 上的另一根杠杆,ONNX Runtime 自己的文档写明了它的两项代价:8 位线性量化不是无损变换;而且它的开销使得在旧设备上性能变差的情况并不少见。对 CTR 模型来说,准确性包括校准,所以要在量化前后对比预测比率与观测比率。

跨请求批处理,花掉的是出价方最缺的资源

把同一个请求的候选做成批次,不需要任何等待,因为它们已经都在了。跨请求的动态批处理靠让请求等待同伴来提高吞吐量,这与竞价时限的要求正好相反,而推理服务器自己也是这么说的:

  • TensorFlow Serving 用 batch_timeout_micros 为未满批次的等待设上限,这个参数用来控制长尾延迟;对于纯 CPU 系统,它建议从 0 开始设置,同时要记住 0 可能就是最优值
  • NVIDIA Triton 的动态批处理器只在没有任何请求的等待时间超过配置的最大队列延迟时,才会继续攒着批次;其指南建议调高这个延迟,直到超出延迟预算为止
  • Triton 的队列策略可以拒绝或推迟在队列中等待超时的请求,把迟到的打分变成出价方能据此采取行动的提前失败

Google 于 2016 年发表的 Wide & Deep 论文,展示了这笔权衡在单个请求之内的那一面,对象是一个目标为在 10 ms 量级内服务每个请求的服务。在单线程上把所有候选放进一个批次打分耗时 31 ms;把这个批次拆成多个更小的批次、在并行线程上处理,把客户端侧延迟降到了 14 ms,其中已包含服务开销。

Clipper 是伯克利在 NSDI 2017 上发表的预测服务系统,它按时限而不是按硬件来确定批大小:以加法方式增大批次,直到处理这个批次的耗时超出延迟目标,然后回退 10%。对出价方来说,要学的是这个顺序:先定下延迟目标,再取能放进这个目标之内的任何批次,哪怕批大小只有一。

用 CPU 还是加速器,由批大小和传输成本决定

加速器要在大批次上才配得上它的位置,而一个竞价请求的批次,只是它筛选后留下的候选。DeepRecSys 是哈佛与 Facebook 在 ISCA 2020 上发表的一项研究,它发现在较大的批大小下 GPU 的性能优于 CPU,并且在它研究的每一个模型上,把输入从 CPU 加载到 GPU 平均占去端到端 GPU 推理时间的 60% 到 80%。

它的调度器并没有只选一种设备:仅在并行 CPU 核上把大查询拆成更小的批次,就在八个具有行业代表性的模型上、在严格的长尾延迟目标下把吞吐量翻了一倍;再只把超过某个大小阈值的查询卸载到 GPU,吞吐量又进一步提高。对出价方来说,每个请求的小批次留在 CPU 上,而加速器必须把传输和排队的代价赚回来。

迟到的预测比朴素的预测更糟,所以先设计降级

Clipper 的 straggler 缓解建立在一个值得照搬的设计选择上:给出一个迟到的预测,比给出一个不准确的预测更糟。到了时限,它的模型选择层会合并已经到达的预测,并用其平均值替代缺失的预测。在出价方里,与之对应的是一道阶梯,而每一级都必须给出一个竞价能够接受的价格:

  • 完整模型:当拉取在其份额之内返回时
  • 不含迟到特征组训练出的精简模型:当拉取被取消时
  • 以广告位、创意和受众分群这类粗粒度上下文为键、带年龄上限的缓存预测:当求值时间不够时
  • 按广告位和创意给出的校准先验:当以上各项都不可用时
  • 带原因码的 no-bid:当连先验都只能算猜测时

对于转化目标,每次展示的期望价值等于点击概率乘以点击后的转化概率,再乘以转化的价值,所以偏高的那一级,出价会高于这次展示的价值:在一价竞价中,它每次胜出都多付钱;在二价竞价中,它会赢下本该输掉的展示。McMahan 等人写道,准确且校准良好的预测是运行竞价所必不可少的,并把训练或服务时不可用的隐藏特征列为系统性偏差的成因之一;而被取消的拉取,就会让一个特征在服务时不可用。

每一级都要计数。按原因拆分的降级率——拉取被取消、求值迟到、命中缓存、先验、no-bid——应当和 p99 放在同一张图上,因为出价方可以悄悄地用先验作答来守住延迟目标,而花费却是按猜测定价的。

先做影子验证,再上带花费上限的金丝雀

新模型会同时改变延迟和价格,而两者在不同的时钟上出问题:延迟在几分钟之内,价格则要经过整个转化窗口。分两步上线,把两者分开:

  • 在独立实例上用镜像流量做影子打分,绝不放在你正在测量其成本的进程内部
  • 在相同的请求上做对比:预测分布、特征缺失率、每个候选的求值耗时,以及每个模型本会出的价格
  • 在一小部分线上流量上跑金丝雀,每条出价日志都带上模型版本,让胜出、花费和转化都能按版本拆分
  • 花费上限,以及按延迟、降级率或偏差触发的自动回滚,因为金丝雀的出价买的是真实的展示

Google SRE Workbook 把金丝雀发布定义为:对服务中的一项变更做部分的、限时的部署,并对其进行评估;它还警告,对于查询多样的系统,只经过寥寥几个查询就结束的金丝雀给不出有用的信号。对转化模型来说,这「寥寥几个」要按转化来数,所以金丝雀至少要运行一个转化窗口那么长。

在同一个仪表盘上监控模型和时钟

延迟监控说明模型有没有作答;模型监控说明这个回答值不值那个价。出价方两者都需要,并按广告交易平台和模型版本切分:

  • 拉取耗时与求值耗时分开做直方图,各自给出 p99 和 p99.9,旁边放按原因拆分的降级率
  • 预测偏差:Google 的 Sculley 等人在 2015 年把它描述为预测标签与观测标签的分布相吻合;一个预测平均值的模型也会通过,所以要切分来看,包括按预测概率分桶
  • 训练-服务偏差:Google 的 Rules of Machine Learning 指出,应当把服务时使用的特征记录下来并用它们训练,至少对一小部分数据这样做
  • 模型年龄:Facebook 2014 年的点击预测论文发现,把训练从每周一次改为每天一次,归一化熵降低了约 1%,并认为每天重训是值得的
  • 出价和花费上的行动限制:2015 年那篇论文建议在现实世界中采取行动的系统设置这类限制,并把出价列为例子之一

在 tmax 之后才到达的预测,产出的并不是一次更慢的出价。它产出的是一次超时、一个对你限流的理由和一张 CPU 账单,而竞价已经由那些作答了的出价方决出。

构建这类系统的公司,在问模型之前先要超时报表

问题的后半部分——谁来构建嵌入出价方的推理管道——有一个不需要供应商名单的判别方法。做这类工作的公司,在给出模型之前会先问预算:

  • 要 tmax 分布、按广告交易平台拆分的超时报表,以及通过定向筛选后剩下的候选数量
  • 在提出运行时方案之前,先写下时限的拆分——网络链路、解析、拉取、求值、余量——并指明它预期长尾出在哪个阶段
  • 把降级阶梯和目标降级率写进与模型同一份文档
  • 把校准当作与排序指标并列的验收标准,并询问训练特征是在哪里记录的
  • 带来在独立实例上做影子验证的方案,以及带花费上限和自动回滚的金丝雀,并且上线后能给出价路径配上人

每一项都是你在第一次谈话里就能要来的文档,而含糊的回答说明预算还没有拆分。

所以第一个问题不是上线哪个模型。而是在超时的那个广告交易平台上,扣掉网络链路和特征拉取之后 tmax 还剩多少,以及剩余时间耗尽时出价方出什么价。

amBrain 可以公开证实的内容:amBrain 是一家软件开发公司,专注于交易平台、撮合引擎、实时竞价系统和娱乐场平台工程。amBrain 自 2019 年起做软件开发;在 AdTech 领域,我们做的是 DSP 开发、实时竞价平台和广告交易平台工程。我们有三种合作方式:整体交付、专属团队,或工程师嵌入你的团队。

手头有类似的设计?

带上您当前的架构和让您担心的故障场景,我们用半小时一起梳理。

相关文章

图片加载失败
AdTech
Sep 10, 2026阅读需 10 分钟

RTB 出价方中的 Go GC 停顿:mark assist、时限与 Rust 决策

阅读全文
图片加载失败
AdTech
Sep 10, 2026阅读需 10 分钟

广告测量在高峰丢事件:接缝、重复键与出价方联表

阅读全文
图片加载失败
AdTech
Mar 5, 2026阅读时长7分钟

AI如何重塑2026年的程序化广告

阅读全文