在讲sparkStreaming之前先思考:如果让自己基于spark实现sparkStreaming该如何做?
(1)首先假设我们的spark实现了如下简单功能
那现在是spark流一定用来一个上面的模板对一批一批的rdd处理,应该是这样的:
(2)上面所示,除了一个静态的RDD 模板,还需要一个动态的时间控制器,将streaming data切成片段应用至模板中。
(3)我们的数据从哪来到哪里去,所以我们还需要一个连接数据输入输出的流
(4)如果对于长时间的运行的streaming程序挂了,我们该如何保证,还需要做任务的保证操作。
总结我们的设计:sparkStreaming应该是4部分组成的:
RDD模板 |
JOB动态 |
数据源 |
容错 |
在sparkStreaming种对应的类是这样的:
RDD模板:
来看RDD模板,既然Dstreaming是rdd的模板,那再Streaming中也肯定对应有transfermation和action两种算子了, 可以认为,RDD
加上 batch 维度就是 DStream
,DStream
去掉 batch 维度就是RDD.
Job动态生成:
在 Spark Streaming 程序的入口,我们都会定义一个 batchDuration,就是需要每隔多长时间就比照静态的 DStreamGraph
来动态生成一个 RDD DAG 实例。在 Spark Streaming 里,总体负责动态作业调度的具体类是 JobScheduler
,在 Spark Streaming 程序开始运行的时候,会生成一个 JobScheduler
的实例,并被 start() 运行起来。JobScheduler
有两个非常重要的成员:JobGenerator
和 ReceiverTracker
。JobScheduler
将每个 batch 的 RDD DAG 具体生成工作委托给 JobGenerator
(
JOB
动态)
,而将源头输入数据的记录工作委托给 ReceiverTracker
(数据源)
。
JOBgenerator干什么?主要负责将receiverTracker的数据放在新的batch中,复制模板,对当前的系统做checkpoint操作。
数据源:
DStream
有一个重要而特殊的子类 ReceiverInputDStream
,
它主要将batch实例化成RDD,同时需要receiver为这个RDD生产数据。ReceiverTracker
分发多个 job(每个 job 有 1 个 task),到多个 executor 上分别启动 ReceiverSupervisor
实例;每个 ReceiverSupervisor
启动后将马上生成一个用户提供的 Receiver
实现的实例来爬取数据。Receiver持续的接受数据,给receiverSuperVisor调用blockGenerator将其积攒成一个块,然后将该块的元数据(数据的id,位置,条数,大小)报给driver的receiverTracker。
容错:
最后来看容错,容错分为driver和executor端。
Exector容错方式有4种:将本机器的数据复制至其他机器(storageLevel);将数据保存至本地文件wal;重新爬取数据(如重新从网站上抓取);丢了就算了
Driver端的数据丢了可就完了,所有的executor数据全部需要重新回放,因此采用checkpoint,将其存入hdfs等可靠设备上。
最后写个wordCount结束本文:
val ssc = new StreamingContext(conf, Seconds(1))
val lines = ssc.socketTextStream("localhost", 9999)
val words = lines.flatMap(_.split(" ")) // DStream transformation
val pairs = words.map(word => (word, 1)) // DStream transformation
val wordCounts = pairs.reduceByKey(_ + _) // DStream transformation
wordCounts.print() // DStream output
ssc.start();
ssc.awaitTermination();