1 | # 构建一个 Spark Streaming 应用程序的4 个步骤 |
构建 Streaming Context 对象
使用 Spark Streaming 需要创建 StreamingContext 对象。Spark Streaming 需要制定处理数据的时间间隔,如 1s,那么 Spark Streaming 会以1s为时间窗口进行数据处理。此参数需要根据用户的需求和集群的处理能力进行适当的设置,它的生命周期会伴随整个StreamingContext 的生命周期且无法重新设置。因此,用户需要从需求和集群处理能力出发,设置一个合理的时间间隔。
1 | SparkConf sparkConf = new SparkConf().setAppName("JavaRecoverableNetworkWordCount"); |
Spark Streaming 有特定的窗口操作,窗口操作涉及两个参数:一个是滑动窗口的宽度(Window Duration);另一个是窗口滑动的频率(Slide Duration),这两个参数必须是 batch size 的倍数。例如以过去 5 秒钟为一个输入窗口,每 1 秒统计一下 WordCount,那么我们会将过去 5 秒钟的每一秒钟的 WordCount 都进行统计,然后进行叠加,得出这个窗口中的单词统计。
创建 InputDStream
如同 Strom 的 Spout 一样,Spark Streaming 需要指明数据源。例如 socketTextStream,Spark Streaming 将以套接字连接作为数据源读取数据。当然,Spark Streaming 支持多种不同的数据源,包括 kafkaStream、flumeStream、fileStream、networkStream 等。
1 | JavaReceiverInputDStream<String> lines = ssc.socketTextStream(ip, port); |
操作 DStream
对于从数据源得到的DStream,用户可以在其基础上进行各种操作,如 WordCount 的操作就是一个典型的单词计数执行流程,即对当前时间窗口内从数据源得到的数据进行分词,然后利用 MapReduce 算法映射和计算,最后使用 print() 输出结果。
1 | JavaDStream<String> words = lines.flatMap(s -> Lists.newArrayList(SPACE.split(s))); |
启动 Spark Streaming
之前的所有步骤只创建了执行流程,程序没有有真正连接上数据源,也没有对数据进行任何操作,只是设定好了所有的执行计算,当 ssc.start() 启动后,程序才真正进行所有预期的操作。
1 | ssc.start(); |
优点
- Spark Streaming 内部的实现和调度方式高度依赖 Spark 的 DAG 调度器和 RDD,这就决定了 Spark Streaming 的设计初衷必须是粗粒度方式的,同时,由于 Spark 内部调度器足够快速和高效,可以快速地处理小批量数据,这就获得准实时的特性。
- Spark Streaming 的粗粒度执行方式使其确保“处理且仅处理一次”的特性,同时也可以更方便地实现容错恢复机制。
- 由于 Spark Streaming 的 DStream 本质是 RDD 在流式数据上的抽象,因此基于 RDD 的各种操作也有相应的基于 DStream 的版本,这样就大大降低了用户对于新框架的学习成本,在了解 Spark 的情况下用户将很容易使用 Spark Streaming。
- 由于 DStream 是在 RDD 上的抽象,那么也就更容易与 RDD 进行交互操作,在需要将流式数据和批处理数据结合进行分析的情况下,将会变得非常方便。
缺点
- Spark Streaming 的粗粒度处理方式也造成了不可避免的延迟。在细粒度处理方式下,理想情况下每一条记录都会被实时处理,而在 Spark Streaming 中,数据需要汇总到一定的量后再一次性处理,这就增加了数据处理的延迟,这种延迟是由框架的设计引入的,并不是由网络或其他情况造成的。
- Spark Streaming 当前版本稳定性不是很好。
总而言之,Spark Streaming 为我们提供了一种崭新的流式处理框架,相信未来随着 Spark Streaming 会在易用性、稳定性以及其他方面有很大的提升。