Spark是基于内存的大数据综合处理引擎,具有优秀的作业调度机制和快速的分布式计算能力,使其能够更加高效地进行迭代计算,因此Spark能够在一定程度上实现大数据的流式处理。 随着信息技术的迅猛发展,数据量呈现出爆炸式增长趋势,数据的种类与变化速度也远远超出人们的想象,因此人们对大数据处理提出了更高的要求,越来越多的领域迫切需要大数据技术来解决领域内的关键问题。在一些特定的领域中(例如金融、灾害预警等),时间就是金钱、时间可能就是生命!然而传统的批处理框架却一直难以满足这些领域中的实时性需求。为此,涌现出了一批如S4、Storm的流式计算框架。Spark是基于内存的大数据综合处理引擎,具有优秀的作业调度机制和快速的分布式计算能力,使其能够更加高效地进行迭代计算,因此Spark能够在一定程度上实现大数据的流式处理。 Spark Streaming是Spark上的一个流式处理框架,可以面向海量数据实现高吞吐量、高容错的实时计算。Spark Streaming支持多种类型数据源,包括Kafka、Flume、trwitter、zeroMQ、Kinesis以及TCP sockets等,如图1所示。Spark Streaming实时接收数据流,并按照一定的时间间隔将连续的数据流拆分成一批批离散的数据集;然后应用诸如map、reducluce、join和window等丰富的API进行复杂的数据处理;最后提交给Spark引擎进行运算,得到批量结果数据,因此其也被称为准实时处理系统。 图1 Spark Streaming支持多种类型数据源 目前应用最广泛的×××式处理框架是Storm。Spark Streaming 最低0.5~2s做一次处理(而Storm最快可达0.1s),在实时性和容错方面不如Storm。然而Spark Streaming的集成性非常好,通过RDD不仅能够与Spark上的所有组件无缝衔接共享数据,还能非常容易地与Kafka、Flume等分布式日志收集框架进行集成;同时Spark Streaming的吞吐量非常高,远远优于Storm的吞吐量,如图2所示。所以虽然Spark Streaming的处理延迟高于Storm,但是在集成性与吞吐量方面的优势使其更适用于大数据背景。 Spark Streaming基础概念 批处理时间间隔 在Spark Streaming中,对数据的采集是实时、逐条进行的,但是对数据的处理却是分批进行的。因此,Spark Streaming需要设定一个时间间隔,将该时间间隔内采集到的数据统一进行处理,这个间隔称为批处理时间间隔。 也就是说对于源源不断的数据,Spark Streaming是通过切分的方式,先将连续的数据流进行离散化处理。数据流每被切分一次,对应生成一个RDD,每个RDD都包含了一个时间间隔内所获取到的所有数据,因此数据流被转换为由若干个RDD构成的有序集合,而批处理时间间隔决定了Spark Streaming需要多久对数据流切分一次。Spark Streaming是Spark上的组件,其获取的数据和数据上的操作最终仍以Spark作业的形式在底层的Spark内核中进行计算,因此批处理时间间隔不仅影响数据处理的吞吐量,同时也决定了Spark Streaming向Spark提交作业的频率和数据处理的延迟。需要注意的是,批处理时间间隔的设置会伴随Spark Streaming应用程序的整个生命周期,无法在程序运行期间动态修改,所以需要综合考虑实际应用场景中的数据流特点和集群的处理性能等多种因素进行设定。 窗口时间间隔 窗口时间间隔又称为窗口长度,它是一个抽象的时间概念,决定了Spark Streaming对RDD序列进行处理的范围与粒度,即用户可以通过设置窗口长度来对一定时间范围内的数据进行统计和分析。如果设批处理时间设为1s,窗口时间间隔为3s,如3图所示,其中每个实心矩形表示Spark Streaming每1秒钟切分出的一个RDD,若干个实心矩形块表示一个以时间为序的RDD序列,而透明矩形框表示窗口时间间隔。易知窗口内RDD的数量最多为3个,即Spark Streming 每次最多对3个RDD中的数据进行统计和分析。对于窗口时间间隔还需要注意以下几点: 以图3为例,在系统启动后的前3s内,因进入窗口的RDD不足3个,但是随着时间的推移,最终窗口将被填满。 不同窗口内所包含的RDD可能会有重叠,即当前窗口内的数据可能被其后续若干个窗口所包含,因此在一些应用场景中,对于已经处理过的数据不能立即删除,以备后续计算使用。 窗口时间间隔必须是批处理时间间隔的整数倍。 图3 窗口时间间隔示意图 滑动时间间隔 滑动时间间隔决定了Spark Streaming对数据进行统计与分析的频率,多出现在与窗口相关的操作中。滑动时间间隔是基于批处理时间间隔提出的,其必须是批处理时间间隔的整数倍。在默认的情况下滑动时间间隔设置为与批处理时间间隔相同的值。如果批处理时间间隔为1s,窗口间隔为3s,滑动时间间隔为2s,如图4所示,其含义是每隔2s对过去3s内产生的3个RDD进行统计分析。 图4 滑动时间间隔、窗口时间间隔、批处理时间间隔综合示意图 DStream基本概念 DStream是Spark Streaming的一个基本抽象,它以离散化的RDD序列的形式近似描述了连续的数据流。DStream本质上是一个以时间为键,RDD为值的哈希表,保存了按时间顺序产生的RDD,而每个RDD封装了批处理时间间隔内获取到的数据。Spark Streaming每次将新产生的RDD添加到哈希表中,而对于已经不再需要的RDD则会从这个哈希表中删除,所以DStream也可以简单地理解为以时间为键的RDD的动态序列。设批处理时间间隔为1s,图5为4s内产生的DStream示意图。 Spark Streaming编程模式与案例分析 Spark Streaming编程模式 下面以Spark Streaming官方提供的WordCount代码为例来介绍Spark Streaming的使用方式。 示例1:

Spark Streaming应用程序在功能结构上通常包含以下五部分,如上述示例1所示。 导入Spark Streaming相关包:Spark Streaming作为Spark框架上的一个组件,具有很好的集成性。在开发Spark Streaming应用程序时,只需导入Spark Streaming相关包,无需额外的参数配置。 创建StreamingContext对象:同Spark应用程序中的SparkContext对象一样, StreamingContext对象是Spark Streaming应用程序与集群进行交互的唯一通道,其中封装了Spark集群的环境信息和应用程序的一些属性信息。在该对象中通常需要指明应用程序的运行模式(示例1中设为local[2])、设定应用程序名称(示例1中设为NetworkWordCount)、设定批处理时间间隔(示例1中设为Seconds(1)即1秒钟),其中批处理时间间隔需要根据用户的需求和集群的处理能力进行适当地设置。 创建InputDStream:Spark Streaming需要根据数据源类型选择相应的创建DStream的方法。示例1中Spark Streaming通过StreamingContext对象调用socketTextStream方法处理以socket连接类型数据源,创建出DStream即lines。Spark Streaming同时支持多种不同的数据源类型,其中包括Kafka、Flume、HDFS/S3、Kinesis和Twitter等数据源。 操作DStream:对于从数据源得到的DStream,用户可以调用丰富的操作对其进行处理。示例1中针对lines的一系列操作就是一个典型的WordCount执行流程:对于当前批处理时间间隔内的文本数据以空格进行切分,进而得到words;再将words中每个单词转换为二元组,进而得到pairs;最后利用reduceByKey方法进行统计。 启动与停止Spark Streaming应用程序:在启动Spark Streaming应用程序之前,DStream上所有的操作仅仅是定义了数据的处理流程,程序并没有真正连接上数据源,也没有对数据进行任何操作,当ssc.start()启动后程序中定义的操作才会真正开始执行。 文本文件数据处理案例 功能需求 实时监听并获取本地home/dong/Streamingtext目录中新生成的文件(文件均为英文文本文件,单词之间使用空格进行间隔),并对文件中各单词出现的次数进行统计。 代码实现

运行演示 第1步,启动Hadoop与Spark。

第2步,创建Streaming监控目录。

在dong用户主目录下创建Streamingtext为Spark Streaming监控的目录,创建后如图6所示。 图6 dong用户主目录下创建Streamingtext文件夹 第3步,在IntelliJ IDEA中编辑运行Streaming程序。在IntelliJ IDEA中创建工程StreamingFileWordCount,编辑对象StreamingFileWordCount,如图7所示。 图7 IntelliJ IDEA中StreamingFileWordCount示意图 由于该示例没有输入参数,因此不需要配置参数,可直接单击右键->单击"Run‘StreamingFileWordCount’ "。 第4步,在监听目录下创建文本文件。在master节点上的/home/dong/Streamingtext中分别创建file1.txt与file2.txt。 file1.txt内容如下:

file2.txt内容如下:

创建后,/home/dong/Streamingtext中内容如图8所示。 图8 Streamingtext文件夹内容示意图 查看结果 终端窗口输出了每个批处理时间间隔(20秒)内,/home/dong/Streamingtext中新生成文件所包含的各单词个数,如图9所示。 图9 StreamingFileWordCount运行结果示意图 网络数据处理案例 功能需求 监听本地节点指定端口传输的数据流(本案例为master节点9999端口的英文文本数据,以逗号间隔单词),每5秒统计一次该时间间隔内收集到的各单词的个数。 代码实现 本案例涉及数据流模拟器和分析器两部分。为了更接近真实的网络环境,首先定义数据流模拟器,该模拟器以Socket方式监听网络中指定节点上的指定端口号(master节点9999端口),当外部程序通过该端口连接并请求数据时,数据流模拟器将定时地从指定文本文件中随机选取数据发送至指定端口(每间隔1秒钟数据流模拟器从master节点上的/home/dong/Streamingtext/file1.txt中随机截取一行文本发送给master节点的9999端口),通过这种方式模拟网络环境下源源不断的数据流。针对获取到的实时数据,再定义分析器(Spark Streaming应用程序),用以统计时间间隔(5秒)内收集到的单词个数。 数据流模拟器代码实现如下:

分析器代码如下:

运行演示 第1步,在IntelliJ IDEA中编辑运行Streaming程序。master节点启动IntelliJ IDEA,创建工程NetworkWordCount,编辑模拟器与分析器。模拟器如图10所示,分析器如图11所示。 图10 IntelliJ IDEA中数据流模拟器示意图 图11 IntelliJ IDEA中分析器示意图 第2步,创建模拟器数据源文件。在master节点创建/home/dong/Streamingtext目录,在其中创建文本文件file1.txt。 file1.txt内容如下: 第3步,打包数据流模拟器。打包过程详见本书4.3.3节。在Artifacts打包配置界面中,根据用户实际scala安装目录,在Class Path中添加下述scala依赖包,如图12所示。

图12 在Class Path中添加scala依赖包 打包后在主目录下生成NetworkWordCount.jar,如图13所示。 图13 在dong用户主目录下生成NetworkWordCount.jar示意图 第4步,启动数据流模拟器。在master节点开启控制终端,通过下面代码启动数据流模拟器。 数据流模拟器每间隔1000毫秒从/home/dong/Streamingtext/file1.txt中随机截取一行文本发送给master节点的9999端口。在分析器未连接时,数据流模拟器处于阻塞状态,终端不会显示输出的文本。 第5步,运行分析器。在master上启动IntelliJ IDEA编写分析器代码,然后单击菜单"Build->"Build Artifacts",通过Application选项配置分析器运行所需的参数,其中Socket主机名为master、端口号为9999,参数之间用空格间隔,如图13所示。 图13 分析器参数配置示意图 配置好参数后返回IntelliJ IDEA菜单栏,单击"Run"->"Build Artifacts"运行分析器。 查看结果 第1步,在master上查看数据流模拟器运行情况。IntelliJ IDEA运行分析器从而与数据流模拟器建立连接。当检测到外部连接时,数据流模拟器将每隔1000毫秒从/home/dong/Streamingtext/file1.txt中随机截取一行文本发送给master节点上的9999端口。为方便讲解和说明,file1.txt中每一行只包含一个单词,因此数据流模拟器每次仅发送一个单词给端口,如图14所示。 图14 在master上模拟器运行结果 第2步,在master的IntelliJ IDEA中查看分析器运行情况。在IntelliJ IDEA的运行日志窗口中,可以观察到统计结果。通过分析可知Spark Streaming每个批处理时间间隔内获取的单词数为5,刚好是5秒内发送单词的总数,并对各单词进行了统计,如图15所示。 stateful应用案例 在很多数据流相关的实际应用场景中,对当前数据的统计分析需要借助于先前的数据处理结果完成。例如电商每间隔10分钟统计某一商品当前累计销售总额、车站每隔3小时统计当前客流总量,等等。此类应用需求可借助于Spark Streaming的有状态转换操作实现。 功能需求 监听网络中某节点上指定端口传输的数据流(slave1节点9999端口的英文文本数据,以逗号间隔单词),每5秒分别统计各单词的累计出现次数。 代码实现 本案例功能的实现涉及数据流模拟器和分析器两部分。 分析器代码:

运行演示 第1步,slave1节点启动数据流模拟器。 第2步,打包分析器。master节点启动IntelliJ IDEA创建工程StatefulWordCount编辑分析器,如图16所示,并将分析器直接打包至master节点dong用户的主目录下,如图17所示。 图16 IntelliJ IDEA中StatefulWordCount示意图

图17 master上的StatefulWordCount.jar示意图 第3步,运行分析器。在master节点开启终端,通过下面代码向Spark集群提交应用程序。 查看结果 第1步,查看slave1上数据流模拟器运行情况。分析器在集群上提交运行后与slave1上运行的数据流模拟器建立连接。当检测到外部连接时,数据流模拟器将每隔1000毫秒从/home/dong/Streamingtext/file1.txt中随机截取一行文本发送给slave1节点上的9999端口。由于该文本文件中每一行只包含一个单词,因此每秒仅发送一个单词给端口。如图18所示。 图18 slave1上数据流模拟器运行示意图 第2步,查看master上分析器运行情况。在master节点的提交窗口中可以查看到统计结果,如图19所示。 图19 master上分析器运行示意图 图中表明截至147920770500ms分析器共接收到14个单词,其中"spark"累计出现3次,"hbase"累计出现5次,"hello"累计出现3次,"world"累计出现3次。由于批处理时间间隔是5s,模拟器每1秒发送1个单词,使得分析器在5s内共接收到5个单词,因此截止至147920771000ms,分析器共收到19个单词,其中"spark"累计出现5次,"hbase"累计出现7次,"hello"累计出现4次,"world"累计出现3次。 第3步,查看HDFS中持久化目录。运行后查看HDFS上的持久化目录/user/dong/input/StatefulWordCountlog,如图20所示。Streaming应用程序将接收到的网络数据持久化至该目录下,便于容错处理。

图20 HDFS上持久化目录示意图 window应用案例 在实际生产环境中,与窗口相关的应用场景很常见,例如电商每间隔10分钟小时统计某一商品前30分钟内累计销售总额、车站每隔1小时统计前3个小时内的客流量等,此类需求可借助Spark Streaming中的window相关操作实现。window应用案例同时涉及批处理时间间隔、窗口时间间隔与滑动时间间隔。 功能需求 监听网络中某节点上指定端口传输的数据流(slave1节点上9999端口的英文文本数据,以逗号间隔单词),每10秒统计前30秒各单词累计出现的次数。 代码实现 本例功能的实现涉及数据流模拟器和分析器两部分。 分析器代码: 运行演示 第1步,slave1节点启动数据流模拟器。 第2步,打包分析器。在master节点启动IntelliJ IDEA创建工程WindowWordCount编辑分析器,如图21,并将分析器直接打包至master节点dong用户的主目录下,如图22所示。

图21 IntelliJ IDEA中WindowWordCount示意图 图22 master上WindowWordCount.jar示意图 第3步,运行分析器。在master节点开启终端,通过下面代码向Spark集群提交应用程序。 查看结果 第1步 在slave1上查看数据流模拟器运行情况。分析器在集群上提交运行后与slave1上运行的数据流模拟器建立连接。当检测到外部连接时,数据流模拟器将每隔1000毫秒从/home/dong/Streamingtext/file1.txt中随机截取一行文本发送给slave1节点的9999端口。由于该文本文件中每一行只包含一个单词和一个逗号,因此每秒仅发送一个单词和一个逗号给端口,如图23所示。 图23 在slave1上数据流模拟器运行示意图 第2步,在master上查看分析器运行情况。在master节点的提交窗口中可以查看到统计结果。在WindowWordCount应用程序启动初期,窗口并没有被接收到的单词填满,但随着时间的推进,每个窗口中的单词数目最终固定为30个。图7.35只是截取了运行结果中的三个批次。由于设定了窗口时间间隔是30s,滑动时间间隔是10s,且数据流模拟器每间隔1s发送一个单词,因此WindowWordCount每间隔10s对过去30s内收到的各单词个数进行统计。图24中截至1479276925000ms分析器对过去30s内收到的30个单词进行统计,其中"spark"累计出现5次,"hbase"累计出现8次,"hello"累计出现9次,"world"累计出现8次。再间隔10s,截至1479276935000ms,分析器对过去30s内收到的30个单词进行统计,其中"spark"累计出现8次,"hbase"累计出现9次,"hello"累计出现7次,"world"累计出现6次。 图24 在master上分析器运行示意图 第3步,查看持久化数据。运行后查看HDFS上的持久化目录/user/dong/input/WindowWordCountlog,如图25所示。Streaming应用程序将接收到的网络数据持久化至该目录下,便于容错处理。