Spark数据处理
Spark作为分布式数据处理的一个开源框架,因其计算的高效性和简洁的API而广受欢迎。一般来说,Spark大部分时候被用来进行批处理。但现在Spark通过其SparkStreaming模块也实现了一定的流处理的功能。
Spark流处理的过程
Spark中的流处理实际上并不是真正的流处理。Spark实现流处理的方法是通过mini-batch来对输入数据进行分块(但这个分块频率非常高以至于能够模拟流处理的过程)。 在进行mini-batch分块的时候,Spark引入了DStream的概念。
所谓的DStream
,或者说Discretized Stream
指的是将连续的流数据分成小块批数据的抽象。这就是我们上面说的mini-batch过程。每一个mini-batch体现为一个所谓的RDD(Resilient Distributed Dataset)。而RDD被 交给Spark executor进行进一步的处理。对每一个mini-batch间隔对应的DStream来说,有且仅有一个RDD被产生。
一个RDD是一份分布式的数据集。我们可以把RDD当成指向集群中真正数据块的指针。
DStream.foreachRDD()
方法实际上是Spark流处理的一个处理及输出RDD的方法。这个方法使我们能够访问底层的DStream对应的RDD进而根据我们需要的逻辑对其进行处理。例如,我们可以通过foreachRDD()
方法来访问每一条mini-batch中的数据,然后将它们存入数据库。
这里需要注意的一点是DStream实际上是一组根据时间被分割出来的数据集合。这里我们可以通过如下两段程序来对比传统的集合和Spark中的时序集合DStream的区别。
userList = [something...]
userList.foreach(lambda user:doSomething(user))
这段程序将会对userList
集合中的每一个元素执行doSomething()
函数。
在流处理问题中,我们所面对的不同情况是我们提前并不知道所有的元素。因此我们无法将它们都放入一个list
中。相反的,我们对于流中的每一个元素执行某种操作,就好像意见饭店不断服务前来吃饭的客人一样。
# A DStream of user
userDStream = ???
# For each RDD batch, process each element in it
userDStream.foreachRDD(lambda userbatch:userbatch.foreach(doSomeThing(user)))
需要注意的是:
-
DStream.foreachRDD()
传给我们的参数是一个RDD[userbatch]
,而不是单个的user。用上面饭店的例子来讲,我们得到的不是一个单个的客人,而是某一个时间段内到来的一波客人。因此我们需要进一步循环来根据需要处理其中每一个user
。 - 我们不能用传统的
for ele in iterable
方法来循环其中的元素。因此我们需要用rdd.foreach()
来分别处理其中每一个user
。
进一步分析Spark的流处理过程:我们拥有几个Spark的executor。对于稳定到来的数据流,Spark Streaming负责根据一定的时间间隔将流输入分成小的数据块(batch),然后Spark将这些小数据块(mini-batch)分配给不同的executor,就像饭店将不同的顾客分配给不同的服务员一样。通过这样的操作,Spark实现了并行的数据计算,从而加速了数据处理的速度。