链接
和Spark类似,Spark Streaming通过Maven Central提供。为编写Spark Streaming程序,需要添加下面的依赖到你的SBT或者Maven工程中。
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.11</artifactId>
<version>2.1.1</version>
</dependency>
libraryDependencies += "org.apache.spark" % "spark-streaming_2.11" % "2.1.1"
从Kafka,Flume和Kinesis获取数据不在Spark Streaming的核心API中,需要添加相应的artifact spark-streaming-xyz_2.11依赖。例如,常用的依赖如下:
Source | Artifact |
---|---|
Kafka | spark-streaming-kafka-0-8_2.11 |
Flume | spark-streaming-flume_2.11 |
Kinesis | spark-streaming-kinesis-asl_2.11 |
更新列表请参见Maven repository。
初始化StreamingContext
初始化Spark Streaming程序,必须创建StreamingContext对象,作为Spark Streaming程序的主入口点。
从SparkConf对象创建StreamingContext对象。
import org.apache.spark._
import org.apache.spark.streaming._
val conf = new SparkConf().setAppName(appName).setMaster(master)
val ssc = new StreamingContext(conf, Seconds(1))
appName
参数是应用程序名称,显示在集群UI上。master
是一个Spark, Mesos或YARN集群URL,或者一个特殊的“local[*]”字符串,以本地模式运行。实际上,当运行在集群上时,是不希望在程序中硬编码master
的,而是使用spark-submit启动应用程序
接收master
参数。不过为了本地测试和单元测试,可以传”local[*]”来运行Spark Streaming(在本地系统检测CPU核数)。注意,这里内部创建了一个SparkContext(Spark程序的起始点),可以通过ssc.sparkContext
访问。
批时间间隔必须根据应用程序的延迟需求和集群可用资源来设置。具体参见性能调优。
StreamingContext
对象也可以通过已经存在的SparkContext
对象创建。
import org.apache.spark.streaming._
val sc = ... // existing SparkContext
val ssc = new StreamingContext(sc, Seconds(1))
上下文定义完成后,必须做以下事情。
1. 通过创建输入DStream定义输入源。
2. 通过在DStream上应用转换和输出操作定义流计算。
3. 开始接收数据并使用streamingContext.start()
进行处理。
4. 使用streamingContext.awaitTermination()
等待处理结束(手动或者因为错误结束)。
5. 可使用streamingContext.stop()
手动停用处理过程。
需要记住的几点:
- 一旦上下文启动,就不能像其添加新的流计算了。
- 一旦上下文停用,不能重启。
- 同一时间再JVM中只能有一个StreamingContext处于活跃状态。
- StreamingContext的stop()方法也会停用SparkContext。只想停用StreamingContext,设置
stop()
方法的可选参数stopSparkContext
为false。 - SparkContext可以进行重用,创建多个StreamingContext,只要在创建下一个StreamingContext之前停用了前一个StreamingContext(但是没有停用SparkContext)即可。
离散流(DStreams)
DStream是Spark Streaming提供的基本抽象。代表一个连续的数据流,要么是从源接收的输入数据流,要么是转换输入流生成的处理过的数据流。在Spark内部,DStream代表一系列连续的RDD(不可变的分布式数据集,参见Spark编程指南(二)。DStream中的每个RDD包含一定时间间隔的数据,显示如下图。
应用在DStream的任何操作都会转换为潜在RDD的操作。例如,在前面例子中将每行的数据流转换为单词,flatMap
操作应用在lines
DStream中的每个RDD上,生成words
DStream的RDD。显示如下图。
这些潜在的RDD转换由Spark engine进行计算。DStream操作会隐藏大部分这些细节,然后提供给开发者一个高层API方便使用。这些操作会在之后进行详细介绍。
输入DStreams和Receivers
输入DStream代表从源接收的输入数据流。在前面快速示例中,lines
就是输入DStream,它代表了从netcat服务器接收的数据流。每个输入DStream(除了文件流,会在下面进行讨论)都会关联一个Receiver(Scala doc, Java doc)对象,这个对象接收来自源的数据并将数据存储在Spark的内存中供后续处理。
Spark Streaming提供两类内置的源。
- Basic sources:在StreamingContext API中直接可用。例如:文件系统和socket连接。
- Advanced sources:如Kafka,Flume,Kinesis等。通过额外的工具类可用。这些需要链接到额外的依赖项,这个之前已经讨论过。
接下来讨论每个类别中的一些源。
注意,如果你想在streaming应用程序中并行接收多个数据流,可以创建多个输入DStream(在之后性能调优中进行讨论)。这样会创建多个receiver同时接收多个数据流。但是需要注意的是Spark worker/executor是长线任务,它会占用分配给Spark Streaming应用程序的一个CPU核。因此,要记住Spark Streaming应用程序需要分配足够的CPU核(或线程,如果在本地运行)来处理接收到的数据以及运行receiver。
需要记住的几点
- 当本地运行Spark Streaming程序时,不要使用”local”或者”local[1]”作为master URL。这意味着本地只有一个线程用来运行任务。如果你使用基于receiver的输入DStream(例如sockets,Kafka,Flume等等),单线程会用于运行receiver,没有线程会用于处理接收到的数据。因此,当本地运行时,要使用”local[n]”作为master URL,其中n大于receiver的数量(可参考Spark Properties了解如何设置master)。
- 将逻辑扩展到集群上运行,分配给Spark Streaming应用程序的核数必须比receiver的数量多。否则系统会接收数据,但不能处理数据。
Basic Sources
在前面的示例中我们已经看到过ssc.socketTextStream(...)
,从TCP socket连接接收文本数据并创建一个DStream。处理sockets,StreamingContext API还提供了创建以文件作为源的DStream。
- File Streams:从任意兼容HDFS API的文件系统(如HDFS, S3, NFS等等)的文件中读取数据,可以用如下方式创建DStream:
streamingContext.fileStream[KeyClass, ValueClass, InputFormatClass](dataDirectory)
Spark Streaming会监控目录dataDirectory
,处理任意在那个目录中创建的文件(不支持写入嵌套目录中的文件)。请注意:
- 文件必须是相同数据格式。
- 文件必须在
dataDirectory
中创建,通过原子级地移动或重命名文件到数据目录的方式。 - 一旦移动,文件必须不能修改。如果文件正在不断地进行追加,那么新数据不会被读取。
对于简单文本文件,有一个更简单的方法streamingContext.textFileStream(dataDirectory)
。文件流不会要求运行receiver,因此不需要分配CPU核。
基于自定义Receiver的流:可以通过自定义receiver接收数据流来创建DStream。详细请参见Custom Receiver Guide。
RDD队列作为流:对于使用测试数据测试一个Spark Streaming应用程序来说,可以基于RDD队列来创建DStream,使用
streamingContext.queueStream(queueOfRDDs)
。添加到队列中的每个RDD都会被当做DStream中一个批次的数据,像数据流一样进行处理。
对于来自socket和文件数据流的更多细节请参见相关的API文档,scala请参见StreamingContext,Java请参见JavaStreamingContext,Python请参见StreamingContext。
Advanced Sources
这个分类的源要和外部非Spark库交互,其中一些需要复杂的依赖(如Kafka和Flume)。因此,为了尽量减少和依赖库版本冲突的问题,从这些源创建DStream的功能移到了单独的库中,必要时可以显式链接。
注意这些高级源在Spark shell中不可用,因此基于高级源的应用程序不能在shell中测试。如果想要在Spark shell中使用高级源,需要在下载对应的Maven artifact’s JAR以及其依赖的库,然后添加到classpath中。
一些高级源如下:
- **Kafka:**Spark Streaming 2.1.1和Kafka broker 0.8.2.1及更高版本兼容。具体参见Kafka Integration Guide。
- **Flume:**Spark Streaming 2.1.1和Flume 1.6.0版本兼容。具体参见Flume Integration Guide。
- **Kinesis:**Spark Streaming 2.1.1和Kinesis Client Library 1.2.1兼容。具体参见Kinesis Integration Guide。
Custom Sources
输入DStream也可以通过自定义数据源创建。你需要实现用户定义的receiver(下面会进行说明)用于接收自定义源的数据并将数据存储到Spark中。具体参见Custom Receiver Guide。
Receiver可靠性
有两类基于可靠性的数据源。数据源(如Kafka和Flume)允许确认传输的数据。如果系统从这些能确认数据正确接收的可靠源接收数据,则可以确保不会有数据因为任何类型的失败而丢失数据。下面是两类receiver:
1. 可靠Receiver - 当数据已经接收并且按照副本要求存储到Spark中时,可靠receiver会正确发送确认信息给可靠数据源。
2. 不可靠Receiver - 不可靠数据源不能发送确认信息给数据源。这类receiver用于不支持确认的数据源,或者对于可靠数据源,不想或不需要进行确认。
如何编写可靠receiver在中Custom Receiver Guide进行讨论。