一个必须在每个竞价请求之内作答的 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% 的请求。在竞价之内,对冲延迟必须从拉取剩余的份额里出。
选运行时,主要是在决定在哪里求值。独立的推理服务器会给每个要打分的请求加上一次往返和一个队列;在出价方进程内部求值,两样都不加,取而代之的是把它的内存和线程交到你手上。四种常见选择:
量化是 CPU 上的另一根杠杆,ONNX Runtime 自己的文档写明了它的两项代价:8 位线性量化不是无损变换;而且它的开销使得在旧设备上性能变差的情况并不少见。对 CTR 模型来说,准确性包括校准,所以要在量化前后对比预测比率与观测比率。
把同一个请求的候选做成批次,不需要任何等待,因为它们已经都在了。跨请求的动态批处理靠让请求等待同伴来提高吞吐量,这与竞价时限的要求正好相反,而推理服务器自己也是这么说的:
Google 于 2016 年发表的 Wide & Deep 论文,展示了这笔权衡在单个请求之内的那一面,对象是一个目标为在 10 ms 量级内服务每个请求的服务。在单线程上把所有候选放进一个批次打分耗时 31 ms;把这个批次拆成多个更小的批次、在并行线程上处理,把客户端侧延迟降到了 14 ms,其中已包含服务开销。
Clipper 是伯克利在 NSDI 2017 上发表的预测服务系统,它按时限而不是按硬件来确定批大小:以加法方式增大批次,直到处理这个批次的耗时超出延迟目标,然后回退 10%。对出价方来说,要学的是这个顺序:先定下延迟目标,再取能放进这个目标之内的任何批次,哪怕批大小只有一。
加速器要在大批次上才配得上它的位置,而一个竞价请求的批次,只是它筛选后留下的候选。DeepRecSys 是哈佛与 Facebook 在 ISCA 2020 上发表的一项研究,它发现在较大的批大小下 GPU 的性能优于 CPU,并且在它研究的每一个模型上,把输入从 CPU 加载到 GPU 平均占去端到端 GPU 推理时间的 60% 到 80%。
它的调度器并没有只选一种设备:仅在并行 CPU 核上把大查询拆成更小的批次,就在八个具有行业代表性的模型上、在严格的长尾延迟目标下把吞吐量翻了一倍;再只把超过某个大小阈值的查询卸载到 GPU,吞吐量又进一步提高。对出价方来说,每个请求的小批次留在 CPU 上,而加速器必须把传输和排队的代价赚回来。
Clipper 的 straggler 缓解建立在一个值得照搬的设计选择上:给出一个迟到的预测,比给出一个不准确的预测更糟。到了时限,它的模型选择层会合并已经到达的预测,并用其平均值替代缺失的预测。在出价方里,与之对应的是一道阶梯,而每一级都必须给出一个竞价能够接受的价格:
对于转化目标,每次展示的期望价值等于点击概率乘以点击后的转化概率,再乘以转化的价值,所以偏高的那一级,出价会高于这次展示的价值:在一价竞价中,它每次胜出都多付钱;在二价竞价中,它会赢下本该输掉的展示。McMahan 等人写道,准确且校准良好的预测是运行竞价所必不可少的,并把训练或服务时不可用的隐藏特征列为系统性偏差的成因之一;而被取消的拉取,就会让一个特征在服务时不可用。
每一级都要计数。按原因拆分的降级率——拉取被取消、求值迟到、命中缓存、先验、no-bid——应当和 p99 放在同一张图上,因为出价方可以悄悄地用先验作答来守住延迟目标,而花费却是按猜测定价的。
新模型会同时改变延迟和价格,而两者在不同的时钟上出问题:延迟在几分钟之内,价格则要经过整个转化窗口。分两步上线,把两者分开:
Google SRE Workbook 把金丝雀发布定义为:对服务中的一项变更做部分的、限时的部署,并对其进行评估;它还警告,对于查询多样的系统,只经过寥寥几个查询就结束的金丝雀给不出有用的信号。对转化模型来说,这「寥寥几个」要按转化来数,所以金丝雀至少要运行一个转化窗口那么长。
延迟监控说明模型有没有作答;模型监控说明这个回答值不值那个价。出价方两者都需要,并按广告交易平台和模型版本切分:
在 tmax 之后才到达的预测,产出的并不是一次更慢的出价。它产出的是一次超时、一个对你限流的理由和一张 CPU 账单,而竞价已经由那些作答了的出价方决出。
问题的后半部分——谁来构建嵌入出价方的推理管道——有一个不需要供应商名单的判别方法。做这类工作的公司,在给出模型之前会先问预算:
每一项都是你在第一次谈话里就能要来的文档,而含糊的回答说明预算还没有拆分。
所以第一个问题不是上线哪个模型。而是在超时的那个广告交易平台上,扣掉网络链路和特征拉取之后 tmax 还剩多少,以及剩余时间耗尽时出价方出什么价。
amBrain 可以公开证实的内容:amBrain 是一家软件开发公司,专注于交易平台、撮合引擎、实时竞价系统和娱乐场平台工程。amBrain 自 2019 年起做软件开发;在 AdTech 领域,我们做的是 DSP 开发、实时竞价平台和广告交易平台工程。我们有三种合作方式:整体交付、专属团队,或工程师嵌入你的团队。
带上您当前的架构和让您担心的故障场景,我们用半小时一起梳理。