Spark Streaming使用(Python版)
本文使用的是PySpark,但如果用scala本质思想是一致的,只是语言不同。参考的是子雨老师的教程——子雨大数据之Spark入门教程(Python版)
Spark安装
PySpark版本参考
Spark2.1.0+入门:Spark的安装和使用(Python版)
scala版本参考
Spark Streaming简介
Spark Streaming是Spark的核心组件之一,为Spark提供了可拓展、高吞吐、容错的流计算能力。如下图所示,Spark Streaming可整合多种输入数据源,如Kafka、Flume、HDFS,甚至是普通的TCP套接字。经处理后的数据可存储至文件系统、数据库,或显示在仪表盘里。
Spark Streaming的基本原理是将实时输入数据流以时间片(秒级)为单位进行拆分,然后经Spark引擎以类似批处理的方式处理每个时间片数据,执行流程如下图所示。
Spark Streaming最主要的抽象是DStream(Discretized Stream,离散化数据流),表示连续不断的数据流。在内部实现上,Spark Streaming的输入数据按照时间片(如1秒)分成一段一段的DStream,每一段数据转换为Spark中的RDD,并且对DStream的操作都最终转变为对相应的RDD的操作。例如,下图展示了进行单词统计时,每个时间片的数据(存储句子的RDD)经flatMap操作,生成了存储单词的RDD。整个流式计算可根据业务的需求对这些中间的结果进一步处理,或者存储到外部设备中。
实现WordCount
编写程序
此处仅介绍文件流的输入来源,其它如套接字等可参见子雨老师的教程。
首先创建一个SparkContext,设置使用2个逻辑CPU的线程来本地化运行Spark。
from pyspark import SparkContext, SparkConf
from pyspark.streaming import StreamingContext
conf = SparkConf()
conf.setAppName('TestDStream')
conf.setMaster('local[2]')
sc = SparkContext(conf = conf)
然后创建spark streaming
ssc = StreamingContext(sc, 20) #每20s监听一下
lines = ssc.textFileStream('file:///usr/local/spark/mycode/streaming/logfile') #监听/usr/local/spark/mycode/streaming/logfile目录
处理数据
words = lines.flatMap(lambda line: line.split(' '))
wordCounts = words.map(lambda x : (x,1)).reduceByKey(add)
wordCounts.pprint() #输出结构
启动ssc
ssc.start() #实际上,这行启动监听
ssc.awaitTermination() #ssc.awaitTermination()是无法输入到屏幕上的,但是,为了程序完整性,这里还是给出ssc.awaitTermination
将代码合起来,新建一个wordCount.py,代码如下
from operator import add
from pyspark import SparkContext, SparkConf
from pyspark.streaming import StreamingContext
conf = SparkConf()
conf.setAppName('TestDStream')
conf.setMaster('local[2]')
sc = SparkContext(conf = conf)
ssc = StreamingContext(sc, 20)
lines = ssc.textFileStream('file:///usr/local/spark/mycode/streaming/logfile')
words = lines.flatMap(lambda line: line.split(' '))
wordCounts = words.map(lambda x : (x,1)).reduceByKey(add)
wordCounts.pprint()
ssc.start()
ssc.awaitTermination()
注意事项
- 监听程序只监听”/usr/local/spark/mycode/streaming/logfile”目录下在程序启动后新增的文件,不会去处理历史上已经存在的文件。(这意味着如果把先前已经存在的文件从别的地方拖入到logfile目录下也是无效的——注意理解新增的概念)
- 因此,在开启spark streaming监听之后,需要到”/usr/local/spark/mycode/streaming/logfile”目录下再新建一个log3.txt文件,这时才能看到效果。
扩展(统计包含历史信息)
我们可以发现这每一次输出的数据都只针对当前文件,而与前面处理过的文件无关。但现实情况中,往往需要统计的数据。那要怎么办呢?
一个办法便是使用updateStateByKey操作,这需要我们设置checkpoint以及完成一个updateFunc的函数。
-
checkpoint顾名思义就是我们熟知的检查点,它帮助了updateStateByKey操作的实现。
-
Spark Streaming的updateStateByKey可以把DStream中的数据按key做reduce操作,然后对各个批次的数据进行累加。注意,wordDstream.updateStateByKeyInt每次传递给updateFunc函数两个参数,其中,第一个参数是某个key(即某个单词)的当前批次的一系列值的列表 ,updateFunc函数中 sum(new_values),就是计算这个被传递进来的与某个key对应的当前批次的所有值的总和,也就是当前批次某个单词的出现次数。传递给updateFunc函数的第二个参数是某个key的历史状态信息,也就是某个单词历史批次的词频汇总结果。
改写后的代码
from pyspark import SparkContext, SparkConf
from pyspark.streaming import StreamingContext
def updateFunc(new_values, last_sum):
return sum(new_values) + (last_sum or 0)
conf = SparkConf()
conf.setAppName('TestDStream')
conf.setMaster('local[2]')
sc = SparkContext(conf = conf)
ssc = StreamingContext(sc, 20)
ssc.checkpoint("file:///usr/local/spark/mycode/streaming/")
lines = ssc.textFileStream('file:///usr/local/spark/mycode/streaming/logfile')
words = lines.flatMap(lambda line: line.split(' '))
wordCounts = words.map(lambda x : (x,1)).updateStateByKey(updateFunc)
wordCounts.pprint()
ssc.start()
ssc.awaitTermination()