Apache Spark

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lipeng08/article/details/83662132

Apache Spark

Apache Spark现在已经成为一种统一化的大数据处理引擎,它通过数据共享抽象Resilient Distributed Datasets (RDDs),来支持各种各样的数据处理工作,像SQL查询,batch处理,streaming,machine learning以及graph处理。

Spark编程模型

RDD抽象

最关键的数据抽象是RDDs,它是一堆对象的集合,并被partition到cluster下的多个机器中,并保证数据不丢失。那么问题来了:

  1. 如何创建一个RDD

    spark提供了很多称之为transformations的函数,用来创建RDDs,例如map,filter,groupby等。

  2. 如何操纵RDD

    RDD对外暴露了各种函数式编程API,支持多种语言如Java,Python,R以及Scala。用户只需要向RDD传递一个local function,就可以操纵cluster中的RDDs。

举例如下:

lines = spark.textFile(“hdfs://...”)
errors = lines.filter(s => s.startsWith(“ERROR”))
println(“Totalerrors:“+errors.count())

上面首先通过HDFS的一个文件创建一个RDD,然后调用filter函数来过滤包含ERROR的行,并将行数打印输出。其中比较特别的地方是filter传入的参数,是一个closure(闭包)。在Spark编程中,用户可以向Spark传入各种lib function,user-define functions甚至于外部引用的变量,这些会将这些变量以read-only的方式copy到cluster中的worker节点上。

lazily computed RDDs

不像传统的MR处理程序,需要首先load数据,然后process,再输出。Spark采用了延迟加载RDDs的方式,也就是说只有在真正需要RDD的时候,才会计算RDD,这就为计算优化提供了可能。事实上,用户提交的一个job可看做是对于RDD的数据执行流图,Spark通过分析数据流图,可生成更efficient的数据执行计划。例如如果有多个filter函数集合在一起对某个RDD操作,那么Spark就可以将这几个操作融合成一个。

shared RDDs

RDDs本身作为一种临时对象存在,其也支持persist到内存的操作。对于需要交互式查询的场景,可以首先将RDD persist到memroy中,然后在其上执行各种各样的数据filter操作。

fault-tolerant RDDs

传统的分布式计算系统常使用副本来保证可靠性,而Spark采用了再计算的方式,称之为lineage。每个RDDs都知晓从base RDDs到达当前状态的这一系列的transformations路径图。当发生故障时,RDDs使用这个图重新计算。例如对于上面代码中提到的RDDs,就可以重新执行filter操作来恢复某个parition。
但是有一种shuffle操作(例如reduceByKey),不适用重新计算,因为目标的任何一个partition都是由原始的全部partition经过reduce操作得到,重新计算代价太大。为了应对这种情况,数据生产者会将数据持久化。

无缝对接storage systems

Spark可以使用多种dfs作为persist存储后端,例如HDFS,Hive,S3等。Spark在将数据载入后统一为RDDs,从而提供了组合多种数据源进行数据分析的能力

上层libraries

RDD编程模型提供了分布式的对象collections以及操纵数据的functions API,从而可以在这些基本属性之上构建各种high-level库,下面讨论四种库。

Spark SQL及DataFrames

分析型数据库一般都支持列存,cost-based优化以及query code generations。Spark SQL通过使用与这些数据库相似的数据布局,来利用现有数据库的研究成果,从而创建了Spark的SQL engine以支持SQL查询。另外,Spark进一步利用SQL engine构建了更高层的数据抽象-DataFrames。它在python和R语言很常见,相比RDDs多了数据的scheme,并支持更丰富的操作(如增加列,aggragation等)。所有的这些操作会被翻译到下层的SQL engine,并利用它的各种优化策略。

Spark流处理

Spark原生支持batch processing,通过将batch划分成更小的batches(例如200ms),从而方便的支持流处理。

GraphX

图形处理框架

MLlib

机器学习框架

组合Tasks

所有的这里lib都操纵同一种数据格式:RDDs,因此可将多个task无缝衔接起来,例如使用Spark SQL读取数据到RDD中,然后使用MLLib训练一个model,并将model应用到一个新的stream中,一个tweet的例子如下:

外部Applications

Spark最常见的应用是batch processing,此外还有interactive query,streaming processing,scientific computing等。

Spark的通用性

下面的内容才是Spark的经典,它之所以通用,一定有其内在的通用本质,这篇论文介绍了两种观点:

  1. 模型表达角度

    RDDs是一个通用的模型,可用来emulate任意的分布式计算,并且在很多场合下都是highly efficient。不适用的地方是计算对网络延迟很敏感的场景。

  2. 系统角度

    RDDs将控制权交给外部应用程序,来控制cluster中的瓶颈资源,也就是网络和存储I/O。
    上面的话过于抽象了,后面再仔细说明这两点。

模型表达角度

首先我们知道MapReduce可以模拟任意形式的computation,这是因为任何分布式的computation从本质上来说就是local computation加上occasionally data exchanging。 MapReduce提供了map函数用于local computation,以及reduce函数适用于all-to-all communication。虽然MapReduce是generall,但是在某些情况下它并不高效。这主要来源于两种情况:

  1. 跨时间段的数据共享

    当系统中的A和B需要在不同的时间段共享数据(A->B)时,A需要首先将数据序列化storage中,以供后面的B使用。这种A write and B read操作无疑会拖慢job的运行。针对于此,Spark采用了in-memory 的RDD来获取fast data sharing,从而避免了中间结果的落盘操作,达到类似于"in-memory"的数据共享。

  2. MR自身延迟

    传统的一个MR step的延迟很大,因为它从设计初定位于batch processing。而Spark的MR step的延迟很小,约100ms。当有些应用需要细粒度的迭代步的时候,100ms的延迟是足够应对很多data-intensive的数据应用。

系统角度

典型的Hadoop系统特征

  1. Local Storage

    内存50GB/s, 10-20块硬盘,1GB/s到2GB/s的磁盘带宽

  2. Links

    10Gbps(1.3GB/s)的网络链路,40X慢于内存带宽,2X慢于磁盘带宽

  3. Racks

    一个机架包含20-40台机器,40Gbps-80Gbps跨机架传输,2X-5X慢于机架内传输。

网络和磁盘I/O是瓶颈,也就是说分布式计算最重要的concern是data placement以及跨网络的计算。
RDD提供了一种机制使得Application能够将计算放到接近数据的地方,也就是preferred locations
除了网络和磁盘I/O,CPU在某些情况下成为瓶颈,Spark在local computation的时候,使用的是native的高度优化的local lib。


  • [1] Zaharia M, Xin R S, Wendell P, et al. Apache spark: a unified engine for big data processing[J]. Communications of the ACM, 2016, 59(11): 56-65.
展开阅读全文

没有更多推荐了,返回首页