前文再续,书接上一回。上回讲到我们是如何获得广告的、如何润色以及如何经过一系列操作确定哪些广告是有资格参与竞价的。在这一篇文章中,我们会继续看看第四到第八步,着眼于如何获得不同的广告报价、如何控制投放节奏、以及鉴定哪些广告最终获得展示。
第四步:投放控制
控制投放的节奏对于所有的广告服务来说,都是至关重要的步骤之一。广告主想让他们的广告活动能在一天中均匀地投放,希望能够尽可能地接触到数量大且多元化的受众。
我们通过 Akka Actor 来维护各个广告活动的花销和预算信息。考虑到花销是一个单调递增的操作,而且最终一致性对于这种信息在我们的业务里面是可以接受的,Akka 分布式数据(Akka Distributed Data)里面的无冲突可复制数据结构(CRDT,Conflict-free replicated data type)成为了存储开销信息的一个不错选择,哪怕是跨数据中心的场景。在校验确定广告活动没有超出它的预算以后,我们还要加载用 Spark 根据过往历史离线计算好的开销预测数据。在 Pacing 这个 Graph 的实现里头,我们使用一个很简单的控制理论衍生技术去决定要不要某个广告参与这次竞价。
上面说的预测数据的主要目的是为了控制一天之中流量是怎么分配的。预测数据的生成会以所有我们知道的主要投放目标为依据,基于相关广告领域知识,结合流量模式和我们能投放的广告位数量来进行计算。举个例子,我们的 App 跑在游戏主机上和手机上的流量模式是完全不一样的。
第五步:搜集出价
Tubi 的广告位有些由我们自己的销售团队负责直接销售(他们组也在招人哦!),也有些通过程序化购买跟第三方需求方平台(DSP)进行集成、销售。这些跟第三方广告平台的集成,自然涉及到对第三方的调用。这些调用肯定会涉及发送网络请求和解析他们返回回来的各种形式的响应。
把上述这些请求封装到他们自己的 akka-stream 流里头,使得我们又一次可以写一些公共的 Graph 来抚平那些复杂逻辑,比如说:异步网络调用、并发控制、错误处理、限流、熔断等等。然后,我们就可以专注于具体的业务逻辑,确保代码能跟第三方那些怪癖接口集成,以及不同人对 IAB(Interactive Advertising Bureau,互动广告局)标准的不同理解造成的实现不同都得到测试。类似地,因为这部分是有严格并发上限的网络请求 Flow,某一个第三方的非预期表现不会影响我们广告系统其他部分的正常工作。
第六步:广告视频的转码
当我们搜集到所有的出价以后,我们会检查我们是不是已经转码了这些出价对应的广告视频。如果还没有转码,我们会进行一个转码操作。之所以要进行转码,主要有以下考虑:
-
作为一家视频公司,我们精修视频播放,所以希望广告也可以在所有 Tubi App 跑的地方也流畅播放;
-
有些广告声音音量可能过大,我们会作相应调整,以使对用户来说不至于震耳欲聋;
-
我们同时希望广告的分级跟内容的分级相匹配。比如说,烟草广告不应该出现在 PG-13 (青少年分级)的内容里头;
-
对于程序化购买进来的广告,比如来自需求方平台(DSP),我们希望可以识别出他们的品牌。一方面为了报表使用,另外一方面也为了更好地控制相同广告的投放频率。
这些步骤的都有属于它们自己的独立服务和相关的机器学习模型,我们以后为他们写单独的文章分享。我们的广告平台,跟其他所有 Tubi 的服务一样,通过 gRPC 跟他们进行通讯,99% 的请求的 SLA 在 10ms 以下。
第七步:竞价
现在就到了,我们广告请求最重要的步骤之一(或者没有之一):竞价。我们有好多个出价等待处理,可能来自多个不同的合作伙伴和内部广告活动,而我们要做的事情是,快速地确定哪些出价应该填充我们的 1 到 5 个广告位。相对于广告请求的其他部分繁重的网络 I/O、缓存、并发之类的问题,竞价的处理却是 100% CPU 操作,用以解决一个复杂的条件约束优化问题。下面举一个简单的例子:这里有一个 n * k 的矩阵,表示有 n 个出价(行)竞逐一次广告请求里的 k 个广告位(列)。
矩阵中每一个格子的取值可以是 1 或者 0,表示某一个竞价在某一个广告位上是否被选中。这样就可以通过一些简单加法表示这种竞价限制了。比如我们需要限定某一个广告主的多个出价只能赢一次,那么就可以限制他出价的所有行之和不能大于 1。类似地,为了确保每个广告位只有一个赢的出价,我们限制每一列的格子之和小于等于 1。更多一些像独立竞价隔离、某些广告竞争的用户体验保证等等都是可以通过这种办法设定的。一个解析器会孜孜不倦地根据我们设定好的限制去优化我们的目标函数。而这个目标函数,是一个营收最大化的线性规划问题,同时包含一些特定的投放保证限制。
第八步:渲染结果
在最后一个步骤,我们会把赢出的竞价渲染为适合每个平台展示的广告。比如我们的有些平台喜欢用 VAST 格式,有一些喜欢用 JSON 格式。通过使用 akka-http 的渲染机制,我们可以定制各种我们需要的模版。
第九步:加入 Tubi
与买办解决方案相比,Tubi 自己的广告技术栈是我们利用自有技术做出优秀产品的众多例子之一。如果你热衷于分布式系统和 Scala 响应式程序设计,我们在积极招聘哦,请加入我们!除了广告技术以外,我们也用同样的技术建设我们的机器学习、大数据等平台。
原文:Marios Assiotis, Tubi CTO,点击 “阅读原文” 查看英文版
译者:Yingyu Cheng, Tubi Senior Scala Engineer
Tubi 拍了拍你,邀请你****加入我们的大家庭!
目前开放的职位:
-
高级数据开发工程师
-
高级机器学习工程师
-
高级后端工程师 - Elixir 方向
-
高级后端工程师 - Scala 方向
-
高级 Android 工程师
-
高级 iOS 工程师
-
高级前端工程师
-
高级前端工程师 - 多媒体方向
-
高级 QA 工程师
更多职位细节请点击我们的官方网站:chinateam.tubi.tv/,或在 Boss 直聘搜索“比图科技”访问我们的招聘主页。