Apache Pig是在HDFS和MapReduce之上的数据流处理语言,它将数据流处理自动转换为一个DAG(有向无环图)的MapReduce作业流去执行,为数据分析人员提供了更简单的海量数据操作接口。但是在DAG的作业流中,作业之间存在冗余的磁盘读写、网络开销以及多次资源申请,使得Pig任务存在严重的性能问题。大数据处理新贵Spark凭借其对DAG运算的支持、Cache机制和Task多线程池模型等优势,相比于MapReduce更适合用于DAG作业流的实现。腾讯TDW Spark平台基于社区最新Spark版本进行深度改造,在性能、稳定和规模方面都得到了极大的提高,为大数据分析任务提供了有力的支持。

本文将介绍DAG模型的作业流计算任务在TDW Spark与Pig上的实现对比,相比于Pig,TDW Spark执行时间缩短8倍,计算节约45%

介绍

Apache Pig是一个基于Hadoop平台的数据流并行执行平台,它包含了一个用于描述数据流的语言,称为Pig Latin。该语言借鉴了SQL和map/reduce两者的优点,既具有类似SQL的灵活可变式性,又有过程式语言的数据流特点,该语言的编译器会将用户书写的Pig Latin脚本转换成一系列MapReduce运算,提供更高层次的抽象将开发者从具体的编程中解放出来,为复杂的海量数据并行计算提供了一个简单的操作接口。

最近风生水起的大数据处理新贵Spark是一个类Hadoop的通用并行计算框架。与Hadoop相比,Spark提供了DAG模型调度来支持复杂的计算任务,通过减少中间结果的磁盘读写和网络传输来获得更佳的性能;提供了cache机制,增加了对迭代计算的支持。Spark还引进了名为RDD(弹性分布式数据集)的分布式内存抽象,使得用户在编写Spark程序时可以像Pig Latin过程式语言这样,轻松操作分布式数据集。

前面介绍了Pig会把Pig Latin脚本翻译成多个MapReduce作业来协作完成,而多个作业之间存在着冗余的磁盘读写开销、网络传输开销和多次资源申请过程。借助于Spark天生支持DAG模型调度和过程式语言编程等特点,本文尝试把一个复杂作业流的Pig计算任务用TDW Spark去实现,并进行性能对比。

实例描述

PV(Page View)和UV(Unique Visitor)统计是数据分析人员在产品运营中使用最为广泛的统计数据之一。本文将以手Q平台公众帐号的推送文章PV、UV统计作为例子,输入数据可以抽象为三张表:手Q平台文章推送表,该表记录了手Q平台的文章下推数据;公众帐号表,记录了各个公众帐号的详细信息;手Q平台推送文章点击表,该表记录了推送文章的点击数据。

先将公众账号表分别和文章推送表、推送文章点击表进行关联过滤数据,再对关联后的新表进行groupby等操作进行数据统计。统计的结果表数据包括:整个手Q平台全部公众帐号以及各个公众帐号的总推送文章量、总推送用户量、推送文章的PV、推送文章的UV、点击率。

Pig解决方案

由于篇幅有限,Pig脚本的处理逻辑不详细介绍,这里主要从数据流的角度描述Pig脚本对数据的加工流程,如下图:

如上数据流图,这是一个存在复杂数据流操作的Pig脚本,由于Pig提供了管道式的数据处理方式,使得数据处理流程简洁直观。通过Pig的客户端日志,可以得到Pig Latin编译器把Pig脚本翻译成的MapReduce Job DAG图:

Pig脚本最终被翻译成一个包含14个MapReduce作业的DAG作业流图来共同完成计算。需要注意,当MapReduce作业的输入输出存在关联时,作业之间是通过HDFS作为中间层来进行协作的,即MR1的结果要先写到HDFS,然后MR2再从HDFS读取MR1的结果来进行运算。14个MapReduce作业意味着14次读写HDFS,同时,MapReduce作业和map/reduce Task的启动也是需要消耗集群调度资源开销的。这样网络和磁盘的开销、以及MapReduce作业和Task启动的调度资源开销,将会使得整个作业流运行时间增大,作业成本增加,随着Job DAG图越复杂,这样的缺点就越明显。

Spark解决方案

Spark提供了Scala过程式语言的编程方式,跟Pig Latin类似,Spark具有join、grouby、union等数据处理算子,distinct、sum等操作也可以通过对RDD进行简单变换操作来实现。因此用Spark来实现上述的Pig脚本是比较容易的,用Spark编程接口实现上述的业务逻辑如下图所示:

与Pig的实现方式相比,Spark在以下方面优化了作业的运行时间和计算成本:

  • DAG模型调度:Spark的DAG编程模型会把Spark作业自动切分成多个Stage,Stage内部再转化为Task任务集,Stage之间的数据依赖通过Shuffle传递。相比Pig的MapReduce作业流,Spark减少了HDFS作为中间层的读写开销,整个Spark作业只需要读、写HDFS各一次。
  • 资源调度优化:Spark通过DAG编程模型把原来的14个MapReduce作业合成了一个Spark作业。同时,Spark作业在启动后会申请所需的全部Executor资源,所有Stage的Tasks以线程的方式运行,共用Executors,相比于MapReduce作业流方式,Spark减少了Job和Task的资源调度开销。
  • Cache机制:Spark的RDD提供Cache特性,使得RDD的数据可以被重复利用而不用重新计算。
  • 更细粒度的数据操作:例如大表join小表的时候可以通过Spark的广播机制把小表先进行广播到各个计算节点,然后再实现join功能。

效果对比

在本文实现的Spark作业中,Stage的Task数由200-2000不等,本测试将使用100、200、400个Executor,每个Executor使用10G内存(内存太少的话Executor会做full GC从而影响性能)做测试,对比不同Executor下的运行时间和计算成本:

对比Spark和Pig的运行结果,Spark的运行时间和计算成本比Pig都有明显减少,DAG模型减少了HDFS读写、cache减少重复数据的读取,这两个优化即能减少作业运行时间又能降低成本;而资源调度次数的减少能提高作业的运行效率。

对比Spark在不同计算资源下的结果,可以看到随着使用的Executor数目增多,Spark的运行时间得到了减少,但是计算成本也随之增大。当Executor数从100翻倍到200,再到200翻倍到400,运行时间并没有得到线性增加,这是由两个因素导致的:(1)每个Task的运行时间并不是完全相等的,例如某些Task处理的数据量比其他Task多,这可能导致Stage的最后时刻因某些Task未结束而无法启动下一个Stage;(2)部分Stage的Task少于400个,因此多出的Executor并没有起到并行执行Task的作用。另一方面,Spark作业是一直占有Executor的,当Stage的Task个数少于Executor时,空闲的Executor也是占用计算成本的,于是会导致计算成本的增加。因以在Spark中运行时间和计算成本是需要开发者根据实际情况去权衡的。

小结

在实际的生产任务中,绝大多数的Pig脚本都会转换成包含多个MapReduce作业的DAG作业流去执行,任务的处理逻辑越复杂,MapReduce作业流的性能问题就会越严重,最终影响任务的运行时间和计算成本。针对这些任务,如果利用Spark的迭代计算和内存计算优势,将会大幅降低运行时间和计算成本。TDW目前已经维护了千台规模的Spark集群,并且会在资源利用率、稳定性和易用性等方面做进一步的提升和改进,为业务提供更有利的支持。

文章来源于腾讯云开发者社区,点击查看原文