摘要:本文整理自 Disney 广告智能执行总监郝又超、Disney 广告智能实时计算负责人李丁哲,在 FFA 主会场的分享。本篇内容主要分为四个部分:
Disney 流媒体广告与实时应用
业务场景实现
实时平台构建
未来展望
Tips:点击「阅读原文」查看原文视频&演讲 ppt
01
Disney 流媒体广告与实时应用
说到 Disney 流媒体业务包括 Hulu,大家可能并不熟悉,因为我们在国内的业务并没有落地。Hulu 是在 15 年前由 Disney、福克斯和 NBC 共同发起成立的,现在已经在美国本土是一家头部的流媒体平台了。
2019 年,Disney 收购了福克斯从而得到的 Hulu 的运营控制权,因此也得到了 Hulu 上的广告平台这样一个优质资源。作为传统的流媒体公司,Disney 原来并没有自己的技术广告平台,而在 2019 年之后,Disney 也陆续的发力线上流媒体,推出了 Disney+,ESPN+,Star+等多个流媒体品牌。下面来具体看一下 Disney 和 Hulu 的流媒体以及广告业务的数据。
2.35 亿,是截止到今年十月份,Disney 流媒体包括 Disney+,Hulu,ESPN+,Star+在全球的订阅用户。这是一个什么概念呢?Netflix 已经在全球运营了超过十年,我们在今年 7 月份就已经超过了它全球的订阅用户数,且我们的订阅用户数是以家庭为单位的,所以实际触达的个人用户可能有 7 -10 亿。
Hulu 是当前 Disney 流媒体广告业务的主要来源,每天投放数亿 15 秒、30 秒长的视频广告,而每选择一个广告都会产生几十甚至上百个事件,对数据平台有着极高的挑战,随着 Disney+上 12 月份即将上线广告,这种挑战预期将数倍增长。
接下来给大家稍微介绍一下 Disney 的流媒体广告数据平台。大概分为两层,一层是底层的数据和算法,另一层是应用和服务。
数据和算法主要包括三部分:
用户数据。主要通过以用户和用户身份为主要维度来汇聚用户的行为数据,从而对数据交换以及广告所需要的定向进行人群圈选的核心能力。
运营数据。主要包括两部分:
-
一部分是通过以广告的曝光为核心,汇聚所有的广告曝光、投放、转化以及用户交互的数据,形成 Event Store。
-
另一方面是通过对 Event Store 在广告的订单维度上进行进一步聚合,提供各种的 KPI。这些聚合通常是实时的,这就是 Flink 在我们广告平台上主要的应用场景。
机器学习平台。主要通过我们丰富的数据,从用户、广告商以及 Disney 的核心的业务指标进行优化。
可以说数据和算法提供的应用和服务,驱动着我们整个广告生命周期的各个环节。比如:
售卖和规划阶段,我们提供库存预测,用户洞察;
投放和交易阶段,我们提供实时的定向、实时的决策、实时的监控和故障定位
报告分析阶段,我们有商务智能、广告的归因和面向广告商的各种报表。
从具体实时应用的角度,我们目前使用 Flink 主要尝试了三个场景,分别是广告决策漏斗、广告曝光监控、广告系统大屏,这三个环节将在后面做具体阐述。
02
业务场景实现
大概在两年前,我们对流计算框架做了一个统一的选型,之前有用到多种的流计算框架,为了实现上面提到的业务需求,最终选择了 Flink。原因有以下几点:
使用 Flink,可以比较灵活的使用它的 vp 的处理或者流式的处理,从而达到我们对于时效性的多种需求。
Flink 它有流批统一的 API,我们可以用 Datastream 对有限流做 Batch 处理,或者对无限流做流式的处理。而且它可以让我们使用同一套代码,大大减少了我们维护代码的压力。
Flink 支持 Exactly Once 语义,结合我们的上下游,可以达到一个从端到端的 Exactly Once 的保证。
Flink 有很多非常好用的编程的接口,比如 Window Functions。
从整个大数据平台上来看,Flink 的定位主要如下图所示。首先从系统及用户侧去把数据收集到多个消息队列中,然后在上面这条 Flink 统一做一个流式计算,计算出业务所需的一些指标,通过数据接口暴露给实时的业务平台、实时的运维平台,以及其他一些系统如广告服务器。在批处理的这一条链路上,除了会用 Spark 生成一些离线的业务报表、离线的对外数据输出,还会用 Flink Batch 做一些指标回填的操作。
下面分享下第一部分最后提到的三个场景。第一个场景是广告决策漏斗,主要面向的是维护人员和开发者。对于广告的决策系统来讲,广告决策是一个相对比较复杂的过程。当用户登录到流媒体平台的时候,我们需要从一个庞大的广告池子里,通过粗排、精排等多个过滤条件,最终给用户选择出一个最适合他的广告。
因此在这么复杂的业务场景中,就萌生出了运维同学、开发同学对错误排查能力的需求。我们把广告决策的整个流程,抽象成了一个广告决策漏斗。我们希望通过前端给运维人员、开发人员展示一些具体的信息,比如在漏斗里是否有投放的机会、广告是否定向成功、是否被过滤掉、最终有没有投放给用户,如果没有投放给用户,失败原因是什么等等。对于这个业务场景我们主要有三个非常需要关注的点。
数据质量。作为一个需要供大家去做 debug 的平台,我们希望我们的数据质量能够得以保证,要不然这个平台将毫无意义,甚至会误导运维人员、 开发人员,使他们做出一些错误的判断。
系统时效。我们不仅希望广告系统在出现问题时,可以及时发现,希望在运维人员更改配置后,或者开发人员修复一些代码 bug 后,可以及时在广告平台上看到变化,来判断是否成功修复了问题。
开销代价。决策漏斗是一个监控平台,我们不希望它消耗太多的计算资源。那么在整体的架构中,首先需要我们的广告服务器将一些决策信息进行一些动态的编码压缩,然后发送到消息队列当中。Flink 从消息队列中统一做拉取,在窗口框架中将它们 Join 起来,还原出决策漏斗。在这之前也做了一些解码的工作,最终将决策漏斗放在前端进行展示。
这一条实时链路在实现的时候,我们使用了 Exactly Once 语义。上下游都是使用的 Kafka,利用 Kafka 的能力获得 Exactly Once 的保证。OLAP 这一套插入数据的系统也是保证了 Exactly Once 从 Kafka 读取到数据库中,最终成功的实现了从端到端的 Exactly Once。
下面这一条离线的批处理链路,只把它当作一个纠错的链路,当我们实时链路有一些 bug ,造成部分数据质量问题时候的一个数据重填以及纠错。在这个离线链路上,我们也是尝试使用了流批一体,使用同一套代码去做这个数据的回填。
总结一下,刚才提到的三点我们最关心的核心问题;
在数据质量方面,我们从业务角度上看,实现了脏数据收集旁路。一旦发现上游传输的数据不对,运维人员就可以及时得到通知,去进行问题排查。然后这一条链路从底层是用 Exactly Once 做的数据质量的保证,保证都是可以信赖的数据。
在开销代价方面,Exactly Once+流批一体也实现了一个 Kappa 的架构。传统 lambda 架构需要做一个常驻的回填纠错。在 Kappa 的架构下,这一部分的计算资源可以被节省下来。
在系统时效方面,我们也做了一些优化,比如优化了 Flink 本身任务的一些性能。像决策信息是由压缩、动态的编码来发送到我们后端的,这里就涉及了一些比较复杂的数据模型,因为它的原生正反序列化比较缓慢,所以我们进行了一个针对性的优化,提高了整体链路的吞吐率。
可能比较熟悉的同学知道,如果使用 Exactly Once,消息的 Transaction Commit 和 Checkpoint 的生成是息息相关的。只有当 Checkpoint 生成的时候,才会把消息 Transaction Commit 到 Kafka 上,所以时效性也跟 Checkpoint 的速度或者 Checkpoint 间隔的大小紧密相关,我们也对此进行了一些针对性的优化。
不同于一般情况下的 Hadoop 生态系统,Hadoop 在 HDFS 做 Checkpoint。在我们这个应用场景下,我们使用的是 AWS 的 S3 存储。Flink on S3 的 Checkpoint,我们是对于这个场景进行一些深度的优化。
除了时效性以外,我们在稳定性方面也解决了一些问题。比如在比较大的被压场景下,可能会有 Checkpoint 过于缓慢,甚至 Kafka Transaction 失效的问题;在 Flink 1.14 版本,Kafka 的 Producer 可能有 Transaction ID 重用的问题;在同时使用 Transaction,也就是 Exactly Once 和流批一体的时候,面临了这两者不是百分百兼容的问题;比如 Checkpoint 和 Transaction Commit 紧密的关系,在 Batch 的情况下我们没有 Transaction 的概念,需要对算子的内部情况和整体的 Flush 做一些特殊的处理。
在这套系统上线后,我们成功的支持了 20 亿/秒的指标生成,2 分钟左右的端到端延迟,数据取用方面毫秒级响应。
第二个场景是广告曝光监控,主要面向的是用户方和广告主。广告主在签订广告合同的时候,通常会有一些定向投放的限制,比如我是一个母婴用品的广告,那就希望投放的人群是妈妈或者女性,还会有一些动态的规则,比如在投放次数上,不希望在同一时间内投放给同一个用户超过多少次;或在同一个用户的会话窗口下,不希望跟竞品广告出现在一起等等需求。
因此我们研发了广告曝光的监控平台,广告主可以在我们的广告曝光监控平台上看到自己广告投放的一些信息。比如广告的投放区域、面向人群、或者当更改了一些定向规则后,广告服务器有没有反映出这些变化等等需求。
那么广告监控具体是如何实现的呢?首先从我们的系统和客户端收集到一些广告选择的上下文信息、用户和广告的一些交互信息到消息队列中。然后使用 Flink 进行流和流的 join,再加上维度表做维度的增强,从而生成了一系列的事实指标。这些事实指标可以包括广告的曝光、独立访客的数量、用户观看频率等等。
基于这些基础的事实指标和一些特定的广告业务规则,我们计算出一些衍生指标,比如广告投递的状况。在离线我们也生成了一些,可能实时比较不容易生成的指标,比如特别多维度的 UV 指标等等。我们把这一系列的指标,统一通过我们的数据接口向外暴露。这个数据呢,一方面给前端使用,另一个方面也会被广告系统使用。
我们现在的广告系统,更多的是由基础和简单的广告曝光计数器和算法,来控制广告投放的速率。如果我们使用有更加丰富维度的曝光信息,可以支持 AB 测试、更加细腻的广告曝光速率控制等场景。所以在整个数据链路中,我们最关心的就是数据的可用性。
对于数据可用性我们主要做了两点。
尝试让 Flink 和我们正在使用的一个元信息系统进行打通,然后我们的其他应用,比如 Spark,Hive 等应用就可以直接使用 Flink 生成的数据了。
我们提供了一个统一的指标接口。那么不同的下游、前端、后端就可以灵活取用我们的指标了。
第三个场景是广告系统大屏。前两个场景更多的是关注某一个广告投放的一个局部,而广告系统大屏更多的是面向管理层,需要对广告系统和广告投放有一个全局的洞察力。
我们使用 Flink 对一些数据源进行处理,然后通过指标接口暴露出来,再基于不同的业务规则,每 5 分钟、每小时、每天的批式处理,最终投放给前端做广告实时大屏展示。
03
实时平台构建
我们的 Flink 实时平台是基于云上开发的,使用 K8s 作为容器的管理系统,Flink Operator 管理 Flink 集群。我们自己研发了 Job submitter 的角色去帮助用户,让他们以自己熟悉的姿势去提交 Flink 任务。
对于在计算平台出现的一些经典问题,我们也都一一解决了。比如当集群资源有限的情况下,有很多大任务,且每个任务都需要大量的资源,我们同时提交每个任务都能拿到一定的资源,但都没能拿到应该拿到资源的时候,会造成任务和任务之间的互锁,这个时候我们使用了 Gang scheduler 就可以将其解决。
除此之外我们还进行了流批作业混部,这样可以最优化资源的利用率。
为了利用云上弹性缩扩容的能力,我们主要创建了三种类型的队列。
常驻任务队列,它主要面向 Flink Streaming 这样的任务,这样的任务通常它的资源使用更加趋于稳定。所以我们为它主要选择了 Reserved 节点,以一个更长的租期去租用这些设备,然后达到更低的使用费率。
批处理任务队列,它主要面向 Flink Batch,Spark Batch 这样的任务。我们主要使用 On demand 节点,以保证我们对 SLA 的要求。
临时任务队列,它主要面向一些低优先级的任务。我们主要使用 Spot 计算节点,这个节点有比较低 SLA 保证。比如在任务运行的过程中,Spot 节点可能会随时撤出,在每次取用 Spot 节点时,也不能完全满足即取即用的需求,因此我们用 SLA 换取了一个更低的费率。
总体来说,这个计算平台也是根据我们不同队列的一个负载去进行一个弹性的一个扩/缩容。
对于用户侧,我们也有相应的平台,比如任务管理、任务详情,可以让用户看到提交到实时平台上的任务状况。
除此之外还提供了日志的管理系统,包括日志搜集、日志查询,满足用户 debug 的需求。
当然我们也有给运维同学的一些平台,比如集群总体指标查看平台以及对每一个任务运行情况、任务指标查询的窗口。
04
未来展望
我们非常关注 Flink 社区的一些技术发展。Flink 未来在我们产品上的一些实用场景,可以归纳为以下几个方面。
全流批一体。目前 Flink 在我们产品上的使用只在局部环节,主要是一些实时 KPI 的生成,这造成了在存储和计算上的资源浪费。因为我们不得不借助 Lambda 的结构来保证流批之间数据的一致性。如果能借助流批一体,希望可以降低我们在存储和计算上的双重成本。
OLAP。目前我们的实时 KPI 返回还是有单独的 OLAP 引擎,未来希望可以通过统一引擎来提高我们开发的效率。
实时归因。对于广告来说,归因是非常重要的一个环节。目前我们所有的归因都还是离线来实现的,但从业务需求上,我们希望能够更快的知道用户转化的原因,所以利用 Flink 在实时归因上对我们也非常重要。
流式机器学习。在数据平台和计算引擎全部迁到实时计算上后,我们也很想尝试流式机器学习。包括在线特征提取、在线模型训练等等。
往期精选
▼ 关注「Apache Flink」,获取更多技术干货 ▼
点击「阅读原文」,查看原文视频&演讲 PPT