基于Kafka Streams构建广告消耗预测系统

标签: bigdata | 发表时间:2017-11-10 08:00 | 作者:
出处:http://itindex.net/relian

大数据

作者:谢健芬

Pinterest 广告工程团队的宗旨是为我们的广告合作商提供最优质的服务体验,而广告超投,是我们极力要解决的问题之一。在Pinterest,我们使用了 Kafka Streams ,可以实现把广告消耗的预测数据在数秒钟的时间内发送给数千个广告投放服务。本文将会先解释什么是超投,然后分享一下我们是如何使用 Kafka Streams 构造预测系统来提供近实时的预测消耗数据、从而降低超投的。

关于超投

当广告主的预算耗尽时,如果他们的广告被继续投放,这多出来的投放部分将无法再进行收费,这种现象被称之为超投。超投会减少其他还有预算盈余的广告主的广告展现机会,从而降低了他们的产品和服务触及潜在顾客的机会。

要降低超投率,应从两个方面着手:

  1. 计算实时消耗:广告曝光展示的信息应在数秒内反馈给广告系统,系统才能及时关闭那些已耗尽预算的广告计划。
  2. 进行消耗预测:除了让已发生的消耗数据及时传达以外,系统还应具备预测未来消耗的能力,在预计某些计划快要达到预算上限的时候,应降低它们的投放速度,从而使计划平滑地到达预算上限。因为已经投放出去的广告会停留在用户界面上,用户依然可以对它进行操作。这种行为的滞后性会让短时间内的广告消耗难以准确地衡量。而这种自然延迟是不可避免的,我们唯一能确信的只有广告投放事件。

我们举个例子来详细说明一下。假设有一个能提供广告投放的互联网公司,广告主X向该公司购买了出价为$0.10元/ 曝光 、预算为$100元/天的广告服务。这意味着该广告每天最多曝光1000次。

大数据

该公司为广告主快速实现了一个简单明了的投放系统:

大数据

当网站上出现新的广告展现机会时,前端会向广告库(ad inventory)请求一条广告。广告库根据广告主X的剩余预算来决定是否投放他们的广告。如果预算仍然充足,广告库将通知前端进行一次广告投放(比如在用户端APP的一个广告位上展示出来)。当用户浏览了该广告后,一个曝光事件会发往计费系统。

然而,当该公司检查他们的收入时,发现事情的进展与预想的并不一样。

广告主X的广告实际展示了1100次,由于预算只有$100,因此平均每次曝光的价格实际只有$0.09元。比计划多出来的100次曝光相当于是免费投放了,而且这些曝光机会本来可以用来展示其他广告主的广告。这就是业界常谈的超投问题。

那么为什么会发生超投?在这个例子中,我们假设是由于结算系统的响应时间太长所导致的。假设系统对一次曝光的处理有5分钟的延迟,从而导致了超投。因此,这个互联网公司采取了一些优化手段来提高了系统性能,结果成功地多赚了$9元!因为它把原本100次无效曝光中的90次让给了其他预算充足的广告主,从而把超投率降低到10/1000 = 1%。

大数据

不久之后,另一位广告主Y也联系了这家公司,并希望以$100元/天的预算、$2.0元/ 点击(例如,一个用户通过点击广告链接到达广告主Y自己的网站)、最多每天50次点击的价格购买广告。这家公司把广告主Y加到他们的广告投放流程里,并在他们的系统增加了点击事件的跟踪。

大数据

一天下来,这家公司的广告系统再次发生了超投。

大数据

结算下来,广告主Y竟然得到了10个免费点击!而这家互联网公司发现,即使结算系统处理速度足够快,但却无法预知一个投放出去的广告是否会被点击,由于缺乏这些未来的消耗信息,超投将永远都无法避免。

本例子中的主人公最后找到了一个非常聪明的解决办法:给每个广告主计算 预测消耗。预测消耗指的是已经投放出去了但尚未发生消耗的那部分。 如果实际消耗+预测消耗>每日预算,则停止该广告主的广告 投放

构建预测系统

初衷

我们的用户每天在Pinterest上进行浏览以获取新的灵感:从个性化推荐,到搜索,再到运营推荐位。我们需要构建一个兼具可靠性和可扩展性的广告系统来进行广告投放,并确保利用好我们广告主的每一笔预算。

需求

我们着手设计了一个消耗预测系统,系统目标如下:

  • 能处理不同的广告类型(曝光、点击)
  • 必须具备每秒能处理数以万计的事件的能力
  • 能向超过1000个消费者广播更新消息
  • 端到端的延迟不能超过10秒
  • 保证100%的运行时间(Uptime)
  • 在工程上应尽量保持轻量和可维护性

为什么选择Kafka Streams

我们评估过不同类型的流式服务,其中也包括 Spark 和 Flink 。这些技术在数据规模上都能满足我们的要求,但对我们来说,Kafka Streams还具备了一些特殊的优势:

  • 毫秒级延迟:Kafka Streams提供毫秒级的延迟保证,这一点是Spark和Flink做不到的
  • 轻量:Kafka Streams是一个没有重度外部依赖(比如专用集群)的Java应用,这会减轻我们的维护成本。

具体实施

下图在高层次上展示了加入了消耗预测之后的系统结构:

大数据

  • 广告投放系统(Ads serving):负责分发广告到用户端、记录广告投放、并从消耗预测服务(”inflight spend” service)中获取预测消耗数据。
  • 结算系统(Spend system):对广告事件进行聚合并把每个广告主的当前消耗信息告知给广告投放系统。
  • 消耗预测服务(Inflight spend):
    • 广告投放记录(Ad insertion input):每发生一次投放,投放系统应向“input” topic发送如下消息:{key: adgroupId, value: inflight_spend},其中:
      • adgroupId是指在相同的预算约束下的广告组的id
      • inflight_spend = price * impression_rate * action_rate,其中:
        • price: 当前广告的出价
        • impression_rate:广告从投放到曝光的转化率的历史经验值。注意并不是每次投放的广告都一定能被曝光给用户
        • action_rate:对按点击付费的广告主来说,这表示用户点击这条广告的概率;对按曝光付费的广告主来说,这个值为1
    • 消耗聚合器(spend aggregator):订阅 “input” topic 并利用Kafka Streams对每个 adgroup 进行消耗数据的聚合。我们使用了一个10秒的窗口(window) 来计算每个 adgroup 的预测消耗。而“output” topic会被投放系统进行消费,当收到新的消息时,投放系统会更新预测消耗的数据。

在实际应用中,我们的消耗预测的准确率非常高。在整个预算预测系统上线之后,我们的超投率明显下降了。下图是我们的实际消耗与预测消耗的一个对比测试结果样例。

大数据

说明:图中的横轴是以3分钟为单位的时间轴;纵轴表示单位时间内的消耗。其中蓝线表示预测消耗,绿线表示实际消耗

一些经验

  1. 窗口(Window)如果取得不好会严重影响性能。我们在使滚动窗口(tumbling  windows)代替原有的跳跃窗口(hopping windows)后得到了18倍的性能提升。最初我们的实现是使用跳跃窗口去计算3分钟内的预测消耗。在我们的实际案例中,一个窗口的大小是3分钟,前进步长是10秒,这样就会产生180秒 / 10秒 = 18个开放窗口。每一个通过Kafka Streams处理的事件会同时更新到18个窗口中,导致很多不必要的计算。为了解决这个问题,我们把跳跃窗口改成了滚动窗口。相比起跳跃窗口,滚动窗口的特点是每个窗口之间不会互相重叠,意味着每收到一个事件只需要更新一个窗口就可以了。因为把更新操作从18减到了1,因此这个窗口类型更换的操作使整体吞吐量增加了18倍。
  2. 信息压缩策略:为了降低对消费者广播的数据量,我们对 adgroup ID进行了差分编码,并使用查找表存储消耗数据。经过压缩后,我们把信息传输大小压缩到原有的四分之一。

结论

使用Apache Kafka Streams来构建预测消耗系统是我们广告基础组件的一个新的尝试,而该系统也达到了高效、稳定、高容错与可扩展的要求。我们计划在未来将会持续探索由Confluent推出的 Kafka 1.0 和 KSQL 并应用到系统设计上。

End.

转载请注明来自36大数据(36dsj.com): 36大数据» 基于Kafka Streams构建广告消耗预测系统

相关 [kafka streams 广告] 推荐:

基于Kafka Streams构建广告消耗预测系统

- - IT瘾-bigdata
Pinterest 广告工程团队的宗旨是为我们的广告合作商提供最优质的服务体验,而广告超投,是我们极力要解决的问题之一. 在Pinterest,我们使用了 Kafka Streams ,可以实现把广告消耗的预测数据在数秒钟的时间内发送给数千个广告投放服务. 本文将会先解释什么是超投,然后分享一下我们是如何使用 Kafka Streams 构造预测系统来提供近实时的预测消耗数据、从而降低超投的.

kafka监控之kafka-run-class.sh

- - 开源软件 - ITeye博客
kafka自带了很多工具类,在源码kafka.tools里可以看到:. 这些类该如何使用呢,kafka的设计者早就为我们考虑到了,在${KAFKA_HOME}/bin下,有很多的脚本,其中有一个kafka-run-class.sh,通过这个脚本,可以调用其中的tools的部分功能,如调用kafka.tools里的ConsumerOffsetChecker.scala,.

使用Java 8 Streams和Spring Data JPA流式传输MySQL结果

- -
2015年10月19日|  KrešimirNesek. 从1.8版开始,Spring数据项目包含一个有趣的功能 - 通过一个简单的API调用,开发人员可以请求将数据库查询结果作为Java 8流返回. 在技​​术上可行并且由底层数据库技术支持的情况下,结果将逐个流式传输,并且可以使用流操作进行处理.

闲扯kafka mq

- - 开源软件 - ITeye博客
本文主要讲解关于kafka mq的设计思想及个人理解. 关于kafka的详细信息,大家可以参考官网的文献 http://kafka.apache.org/documentation.html这是一篇相当不错的文章,值得仔细研读. 第一个问题:消息队列(Message Queue)是干嘛用的. 首先,要对消息队列有一个基本的理解.

Kafka优化

- - ITeye博客
配置优化都是修改server.properties文件中参数值. 1.网络和io操作线程配置优化. # broker处理消息的最大线程数. # broker处理磁盘IO的线程数. 一般num.network.threads主要处理网络io,读写缓冲区数据,基本没有io等待,配置线程数量为cpu核数加1.

Kafka Connect简介

- - 鸟窝
Kafka 0.9+增加了一个新的特性 Kafka Connect,可以更方便的创建和管理数据流管道. 它为Kafka和其它系统创建规模可扩展的、可信赖的流数据提供了一个简单的模型,通过 connectors可以将大数据从其它系统导入到Kafka中,也可以从Kafka中导出到其它系统. Kafka Connect可以将完整的数据库注入到Kafka的Topic中,或者将服务器的系统监控指标注入到Kafka,然后像正常的Kafka流处理机制一样进行数据流处理.

kafka consumer group offset

- - 开源软件 - ITeye博客
     kafka0.9及以前版本kafka offset 保存在zookeeper, 因频繁读写zookeeper性能不高;从0.10开始,主题分区offset存储于kafka独立主题中.     管理监控kafka主题及分区offset至关重要,原网上很开源流行工具KafkaOffsetMonitor、kafka-manager,旧版offset保存于zookeeper,kafka consumer无相应API,从kafka0.10.1.1以后提供相应API读取主题分区offset(也可以调用KafkaClient API,kafka管理API由scala语言编写).

Kafka设计解析(二):Kafka High Availability (上)

- -
Kafka在0.8以前的版本中,并不提供High Availablity机制,一旦一个或多个Broker宕机,则宕机期间其上所有Partition都无法继续提供服务. 若该Broker永远不能再恢复,亦或磁盘故障,则其上数据将丢失. 而Kafka的设计目标之一即是提供数据持久化,同时对于分布式系统来说,尤其当集群规模上升到一定程度后,一台或者多台机器宕机的可能性大大提高,对Failover要求非常高.

GitHub - andreas-schroeder/kafka-health-check: Health Check for Kafka Brokers.

- -
At AutoScout24, to keep the OS up to date of our clusters running on AWS, we perform regular in-place rolling updates. As we run immutable servers, we terminate each broker and replace them with fresh EC2 instances (keeping the previous broker ids).

Kafka编程实例

- - CSDN博客云计算推荐文章
    Producer是一个应用程序,它创建消息并发送它们到Kafka broker中. 这些producer在本质上是不同. 比如,前端应用程序,后端服务,代理服务,适配器对于潜在的系统,Hadoop对于的Producer. 这些不同的Producer能够使用不同的语言实现,比如java、C和Python.