9.5 用开源工具搭建计算广告系统
上面的广告系统架构模块众多、交互复杂,从头搭建并不容易。在大型互联网公司中,这样的广告系统可以精雕细琢,其中的很多模块也都可以进行专门开发。不过,对于初创型企业和变现业务方向尚需探索的企业来说,需要根据最小值原型(Minimum Value Prototype,MVP)的原则,低成本、短平快地搭建系统,然后在实际业务中进行快速迭代。幸运的是,开源社区为搭建广告系统提供了很多不错的工具,利用这些工具可以相当方便地搭建起一个广告系统基础骨架。一般来说,我们可以利用成熟开源工具解决底层通信、数据传输、负载分配等基础问题,从而将精力重点放在与业务逻辑相关的开发上。
图9-3标示出了计算广告系统中经常用到的一些开源工具,为了方便读者在实际工作中的需要,我们将简要介绍一些主要工具在广告系统中的用法。
9.5.1 Web 服务器 Nginx
我们先从在线投放时用到的 Web服务器说起。由于广告系统有高并发、低延迟的性能要求,Nginx(http://www.nginx.org)在多数情形下都是广告系统首选的 Web 服务器解决方案。
Nginx 是一款开源服务器软件,兼有 HTTP 服务器和反向代理服务器的功能。其主要特点在于高性能、高并发和低内存消耗,并且具有负载均衡、高速缓存、访问控制、带宽控制以及高效整合各种应用的能力,这些特性使得 Nginx 非常适合计算广告这种并发很高的互联网服务。
Nginx还提供了fastCGI这一与各种编程语言之间的通信接口,开发者可以很方便地将服务器的功能逻辑用 fastCGI 插件的形式实现,而无需关注响应 HTTP 请求的细节。在广告系统中,用Nginx作为前端Web服务器,而将广告投放机的功能用C/C++语言实现成fastCGI 插件,是一个开发成本较低、性能又很不错的方案。实际上,这一方案已经实现了一个基本的广告投放机,从事最简单的广告投放业务,而其他模块和功能则可以根据需求逐步开发。
有关 Nginx 更详细的介绍和使用方法可以参考参考文献 [70]。其他的相关开源工具还有Apache(http://httpd.apache.org)等。
图9-3 计算广告系统用到的开源工具示意
9.5.2 分布式配置和集群管理工具 ZooKeeper
由于广告系统的流量很大,单台广告投放机往往不能满足需要。在使用多台服务器的时候,会遇到很多诸如配置文件更新、集群上下线管理等分布式环境下的同步问题。ZooKeeper(http://zookeeper.apache.org)是解决这些问题非常有用的开源工具。
ZooKeeper 是为分布式应用建立更高层次的同步(synchronization)、配置管理(con-figuration maintenance)、群组(groups)以及名称服务(naming)的通用工具。它的基础原理是参考文献 [49] 中的 Paxos 算法,而这一算法最早的工业界应用是 Google 开发的Chubby[17]。在编程上,ZooKeeper的设计很简单。所使用的数据模型非常类似于文件系统的目录树结构,简单来说,有点类似于Windows中注册表的结构,有名称、树节点、键/值对等,可以看作一个树形结构的数据库,可以分布在不同的机器上做名称管理。由于ZooKeeper并不传递计算数据而是传递节点的运行状态,所以运行负载很低。
对广告投放机进行集群管理是 ZooKeeper 在广告系统中的典型应用之一:由于某台服务器宕机或者新机器上线,Nginx的负载均衡方案需要及时作出调整。显然,人工地维护响应时间较长,不可避免地会带来一些流量上的损失。利用 ZooKeeper 的 Ephemeral类型节点可以很方便地实现此功能,这方面的参考资料很多,本书不具体介绍。
由于在广泛使用的Hadoop、HBbase、Storm、Flume等开源产品中都需要用到ZooKeeper进行分布式同步,如果把上述开源产品看作各种小动物,ZooKeeper这一命名可以说非常形象。有关ZooKeeper更详细的介绍和使用方法可以参考参考文献[44]。
9.5.3 全文检索引擎 Lucene
大多数广告业务在初始运营阶段并不见得需要一个真正的倒排检索引擎,不过当广告业务开始面向长尾广告主,广告库规模较大时,采用“倒排检索”加“排序”这样的两段式决策过程是必要的(参见 10.1.1 节)。然而,实现一个功能全面、效率较高的倒排索引并不是一件简单的事,并且由于其与核心业务逻辑关系并不大,也可以用开源方案来实现。
在开源工具中,Lucene(http://lucene.apache.org)是比较常用的基于 Java的全文检索工具包。Lucene并不是一个完整的搜索引擎,但是针对计算广告系统的需要,它可以方便地实现全文索引和检索功能。Lucene 能够为文本类型的数据建立索引,其主要功能是替文档中的每个关键词建立索引。另外,Lucene还提供一组解读、过滤、分析文档,编排和使用索引的API。我们选用Lucene,除了它的高效和简单外,还因为它允许用户对其中的关键环节自定义功能逻辑。不过一些特殊的检索算法,如第13章中要介绍的相关性检索,在Lucene中并不能直接支持,还需要在深入理解源代码的基础上改动或者另行开发。有关Lucene更详细的介绍和使用方法可以参考参考文献[57]。
在需要比较强的索引扩展性的情形下,还可以考虑使用 ElasticSearch(http://www.elasticsearch.org),这是一个基于 Lucene 构建的开源、分布式、RESTful 搜索引擎。设计场景主要是在云计算的环境中,能够实现稳定可靠的实时搜索,并具有良好的水平扩展性。
9.5.4 跨语言通信接口 Thrift
图9-2中的各个模块之间广泛地存在数据交换,不过由于各模块需求的不同,有时我们会选用不同的开发语言来分别实现它们;或者由于开源工具的不同,最方便的使用语言也不同。为了方便在不同语言的模块之间实现调用接口,避免应用开发者过多地将精力放在底层通信上,开源社区涌现了若干个跨语言通信接口工具。我们以Thrift为例来介绍。
Thrift(http://thrift.apache.org)被描述为“scalable cross-language services implementa-tion”(可扩展的跨语言服务实现)[67],它有自己的跨机器的通信框架,还提供了一套代码生成工具,可以生成多种编程语言的通信过程代码。Thrift有一种描述对象和服务的界面定义语言(Interface Definition Language,IDL),它提供了一种网络协议,使用这些对象和服务定义的进程之间基于这种网络协议彼此进行通信。Thrift根据IDL的描述可以生成绝大多数流行语言(如C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript等)的代码框架。因此,服务器端实现语言不会影响到客户端,这给复杂的计算广告技术平台不同系统之间的通信提供了很大的便利。
此外,Thrift还提供了实践中非常有用的版本兼容性功能,即服务器端能在不影响现有的客户端的情况下增加数据结构、字段、服务方法和函数参数。这一特性使得大型工程中模块间的依赖性大为减弱,也能够显著降低开发成本。因此,我们建议在计算广告的系统模块之间尽可能采用Thrift这类工具封装接口。
有关 Thrift 的设计原理和更多细节可以参考 [67]。其他的相关开源工具还有 ProtoBuf(http://code.google.com/p/protobuf)、Avro(http://avro.apache.org)等。
9.5.5 数据高速公路 Flume
计算广告这样的个性化系统由于并发很高,产生的日志量也非常大。在这类系统中,应该避免对数据做单点的集中式读写,而是尽量应该让数据的处理形成环形的流动,即由数据高速公路将线上日志准实时地送至离线或在线处理平台,再将处理结果存放在缓存中供线上决策使用。在这样的架构中,一个分布式、高吞吐率的数据传送通道至关重要。
在这类数据传输工具中,Flume(http://flume.apache.org)是比较常用的开源解决方案之一。Flume 是 Cloudera 提供的一个高可用的、高可靠的、分布式的海量日志采集、聚合和传输的系统,它支持在日志系统中定制各类数据发送方,用于分布式地收集和汇总日志数据。Flume 提供了从控制台(console)、RPC(thrift-RPC)、文本(text)、Tail 操作(UNIX tail)、日志系统(syslog,支持 TCP 和 UDP 两种模式)以及命令执行(exec)等数据源上收集数据的能力。同时,Flume还提供了对数据进行简单处理并输出到各种数据接收方的能力。如果广告投放机采用syslog方式记录投放、点击等日志,可以很方便地通过配置Flume将日志传送到Hadoop上。
其他的相关开源工具还有Scribe(https://github.com/facebook/scribe)等。
9.5.6 分布式数据处理平台 Hadoop
图9-2中的离线数据处理部分需要一个能够存储和加工海量数据的基础设施,实际上这也是大多数大数据系统都需要的平台。在开源的这类平台工具中,Hadoop(http://hadoop.apache.org)几乎是工业界的标准选择。Hadoop 的核心架构主要包括 HDFS(Hadoop Dis-tributed File System,Hadoop分布式文件系统)、Hadoop MapReduce和HBase,其中HDFS是GFS(Google File System)[34]的开源实现,MapReduce是Google MapReduce[26]的开源实现,而HBase则是Google BigTable[20]的开源实现。
HDFS 是一种易于横向扩展的分布式文件系统,提供大规模数据文件存储服务,支持PB级数据规模。它可以运行在上万台的通用商业服务器集群上,提供副本容错机制,为海量用户提供性能优秀的存取服务。计算广告系统里的海量日志文件等就是通过 Flume之类的数据高速公路传送,最终存储在HDFS上,为各种离线计算任务提供服务。
Hadoop MapReduce 是一种分布式计算框架,顾名思义,它由两个部分组成:Map 和Reduce。Map是将一个作业分解成多个任务,而Reduce是将分解后多任务处理的结果汇总起来。在程序设计中,一项工作往往可以被拆分成为多个任务,任务之间的关系可以分为两种:一种是不相关的任务,可以并行执行;另一种是任务之间有相互依赖,先后顺序不能够颠倒,这种任务是无法并行处理的。MapReduce 适用于第一种类型,庞大的集群可以看作是硬件资源池,将任务并行拆分,然后交由每一个空闲硬件资源去处理,能够极大地提高计算效率,同时这种资源无关性对于计算集群的横向扩展提供了最好的设计保证。为了降低MapReduce编程的复杂性,人们还开发了Hive、Pig[33,63]等开源工具产品,使用类似于SQL的脚本语言发起各种数据计算任务。
在广告系统中,Hadoop主要承担着离线数据的存储和计算需求,可以说是计算广告系统进行大规模数据处理不可或缺的基础平台。无论是受众定向、点击率预测还是基础的报表生成,都需要在Hadoop上进行大规模的数据处理。因次,关于Hadoop的原理和应用必须深入掌握。有关Hadoop更详细的介绍和学习资料可以参考参考文献[77]。
9.5.7 特征在线缓存 Redis
无论是离线计算的受众定向标签还是点击率模型参数或特征,由于规模比较大,一般来说都无法直接存放在在线广告投放机的内存中,而是要用独立的缓存服务。在线用到的特征缓存有两个显著的特点,首先是往往只需要存储简单的键/值对,其次是大多数情形下需要支持高并发的随机读和不太频繁的批量写。在这样的需求下,Redis(http://www.redis.io)是比较合适的开源工具之一。
Redis也是一种NoSQL数据库,它主要提供的是高性能的键/值存储(key/value store),采用的是内存数据集的方式。Redis 的键值可以包括字符串、哈希、列表、集合和有序集合等数据类型,因此也被称作是一款数据结构服务器(data structure server)。Redis会周期性地把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了主从同步,具有非常快速的非阻塞首次同步、网络断开自动重连等功能。同时,Redis 还具有其他一些特性,其中包括简单的check-and-set机制、pub/sub和配置设置等,使得它能够表现得更像高速缓存(cache)。Redis 还提供了丰富的客户端,支持现阶段流行的大多数编程语言,使用起来比较方便。
在广告系统中使用 Redis,需要注意的一点是,当以批处理方式更新其中内容时,应避免对线上高并发的读请求产生影响,因此有时需要采用多次写入的方案。
有关Redis更详细的介绍和使用方法可以参考参考文献[51]。
9.5.8 流计算平台 Storm
Hadoop 能够处理的数据规模相当可观,但是处理的响应速度却很难保证。因此,在图9-2的在线处理部分,需要一种新型的、能够以数据流的方式对线上日志准实时处理的平台作为基础设施,在这类平台的开源解决方案中,工业界比较常用的是 Storm(http://storm.apache.org)。
广告中需要用到流计算的问题包括在线反作弊、计费、实时受众定向和实时点击反馈等(参见13.3节)。我们希望的解决方案是能够自动地处理各流计算模块间的通信和数据依赖,并能够在数据规模增大时自动进行分布式的负载分配,Storm这样的流计算平台就可以为我们实现上述的需求。流计算的任务逻辑与 MapReduce过程有些类似,熟悉 Hadoop编程的读者也可以比较容易地在 Storm 上开发应用。不过需要注意的是,流计算的任务调度原则和HDFS上的MapReduce不同,流计算是调度数据,让数据在不同的计算节点间流动起来,而 MapReduce是尽可能调度计算以减少数据 I/O。因此,流计算从本质上讲并不是一个可以真正处理海量数据的框架,它的特长仍然在数据处理的响应速度上。
Storm 保证每个消息都会得到处理,而且处理速度很快,每秒可以处理数以百万计的消息,并且可以使用任意编程语言来做开发。另外,Storm 还可以直接部署在在新一代的Hadoop计算调度引擎YARN上,这样可以非常方便地共享一个Hadoop集群的存储功能和计算资源。
其他的相关开源工具还有S4(http://incubator.apache.org/s4)以及下面要介绍的Spark的 Streaming 方式(http://Spark.apache.org/streaming)等,但它们的系统特点和使用场景还是有一定的差别,读者可以自行了解。有关 Storm 更详细的介绍和使用方法可以参考参考文献[2,80]。
9.5.9 高效的迭代计算框架 Spark
Spark(http://spark.apache.org)在最近几年崭露头角,作为一种新兴的大数据计算平台受到越来越多的关注,一些计算广告系统也开始广泛使用 Spark 平台解决一些需要迭代计算的问题。用 Hadoop 进行大规模数据处理在 Map 和 Reduce 两个阶段之间需要用硬盘进行数据交换,因此在需要面对多次迭代才能完成的任务时效率相当低。由于这样的迭代计算任务在计算广告中很常见(参见第10章),如文本主题模型、点击率预估等,我们非常需要一种更适合于迭代计算的框架。
作为一种新型分布式计算框架,Spark的最大特点在于内存计算。Spark的计算模型可以更加精简地描述等价的MapReduce模型,另外由于Spark的数据共享基于内存,因而相对于基于硬盘的Hadoop MapReduce批处理计算,其性能有数量级的提升。此外,Spark可以在一套软件系统上支持多种计算任务,除了传统的 Hadoop MapReduce 所对应的批处理计算之外,还支持各种机器学习算法为代表的迭代型计算、流式实时计算、社交网络中常用的图计算、SQL关系查询、交互式即席查询等。这样,使用Spark就可以避免同时维护多套针对不同计算需求的系统,还可以避免不同系统之间的数据转储,大大减低了开发和运维成本。
虽然 Spark 可以在很多中等规模的迭代计算问题上表现的性能非常优异,但是由于大量数据的基础存储仍然要依赖于Hadoop,在两个集群之间调度数据成为高效处理数据的障碍。不过,与 Storm 一样,现在 Spark 也已经可以直接部署在 YARN 之上,以“Spark on YARN”的方式与Hadoop方便地共享集群的存储功能和计算资源。
有关Spark更详细的介绍和使用方法可以参考参考文献[21,45]。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论