DStream 的创建
1. 文件输入源
1.1 注意事项
- 监控的⽂件夹内的所有⽂件必须有相同的数据集格式 。
- 监控的⽬录下创建的⽂件必须是移动或者重命名得到的,如果修改已经存在的⽂件的内容则⽆法被监控到。
- ⼀旦⽂件创建成功, 则不能去更改,所以, 如果在⽂件内追加内容, 追加的数据是不能被
Spark Streaming
读到的。 streamingContext.textFileStream(dataDirectory)
可以专⻔⽤来读取⽂本⽂件。
1.2 读取 HDFS 目录下的文件
-
在
HDFS
上创建目录/DStreamInput
。 -
在该目录下创建多个文本文件,在文件内添加一些文本内容。
-
编写代码:
import org.apache.spark.SparkConf import org.apache.spark.streaming.dstream.DStream import org.apache.spark.streaming.{Seconds, StreamingContext} object HDFSFile { def main(args: Array[String]): Unit = { val conf = new SparkConf().setMaster("local[*]").setAppName("HDFSFile") // 1.创建 SparkStreaming 的入口对象 val streamingContext = new StreamingContext(conf, Seconds(3)) // 2.获取 HDFS 上的数据 val input: DStream[String] = streamingContext.textFileStream("hdfs://hadoop101:9000/DStreamInput/") // 3.WordCount val output: DStream[(String, Int)] = input.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_) // 4.输出结果 output.print() // 5.启动:开始接收数据并计算 streamingContext.start() // 6.等待程序结束(手动退出 OR 出现异常)后退出主程序 streamingContext.awaitTermination() } }
2. RDD 队列
-
可以通过使用
streamingContext.queueStream(queueOfRDDs)
创建DStream
,每一个推送到这个队列中的RDD
,都会作为一个DStream
处理。 -
编写代码:
import org.apache.spark.rdd.RDD import scala.collection.mutable import org.apache.spark.streaming.dstream.InputDStream import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.streaming.{Seconds, StreamingContext} object RDD2DStream { def main(args: Array[String]): Unit = { val conf: SparkConf = new SparkConf().setAppName("RDD2DStream").setMaster("local[*]") // 1.创建 streamingContext 的入口对象 val streamingContext = new StreamingContext(conf, Seconds(3)) // 2.获取 sparkContext,为后续创建 RDD 做准备 val sparkContext: SparkContext = streamingContext.sparkContext // 3.创建可变队列 val RDDQueue: mutable.Queue[RDD[Int]] = mutable.Queue[RDD[Int]]() // 4.获取DStream val input: InputDStream[Int] = streamingContext.queueStream(RDDQueue, false) // 5.输出结果 input.print() // 6.启动 streamingContext.start() // 7.创建 RDD 并入队 for (i <- 1 to 5) { val rdd: RDD[Int] = sparkContext.makeRDD(Array(i)) RDDQueue.enqueue(rdd) } // 8.等待程序结束(手动退出 OR 出现异常)后退出主程序 streamingContext.awaitTermination() } }
3. 自定义数据源
-
需要继承
Receiver
,并实现onStart、onStop
方法来自定义数据源采集。 -
需求:自定义数据源,实现监控某个端口号,获取该端口号的内容。
-
编写代码:
3.1 自定义数据源
import java.io.{BufferedReader, InputStreamReader} import java.net.Socket import java.nio.charset.StandardCharsets import org.apache.spark.storage.StorageLevel import org.apache.spark.streaming.receiver.Receiver object MySource { def apply(host: String, port: Int): MySource = new MySource(host, port) } class MySource(host: String, port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY) { /*接收器启动的时候调⽤该⽅法, 这个函数内部必须初始化⼀些读取数据必须的资源 该⽅法不能阻塞, 所以,读取数据要在⼀个新的线程中进⾏. */ override def onStart(): Unit = { // 启动一个新的线程来接收数据 new Thread("Socket Receiver") { override def run(): Unit = { receive() } }.start() // 此方法用来接收数据 def receive() = { val socket = new Socket(host, port) val reader = new BufferedReader(new InputStreamReader(socket.getInputStream, StandardCharsets.UTF_8)) var line: String = null // 当 receiver 没有关闭,且 reader 读到了数据则循环发送给 spark while (!isStopped() && (line = reader.readLine()) != null) { // 发送给 spark store(line) } // 循环结束,则关闭资源 reader.close() socket.close() // 重启任务 restart("trying to connect again") } } override def onStop(): Unit = {} }
3.2 使用自定义数据源
import org.apache.spark.SparkConf import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream} import org.apache.spark.streaming.{Seconds, StreamingContext} object MySourceDemo { def main(args: Array[String]): Unit = { val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("MySourceDemo") val streamingContext = new StreamingContext(conf, Seconds(5)) val input: ReceiverInputDStream[String] = streamingContext.receiverStream(MySource("localhost", 9999)) val output: DStream[(String, Int)] = input.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_) output.print() streamingContext.start() streamingContext.awaitTermination() } }
4. Kafka 数据源
-
需求:通过
Spark Streaming
从Kafka
读取数据,并将读取到的数据做简单计算,最终打印结果。 -
导入依赖
<dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-8_2.11</artifactId> <version>2.1.1</version> </dependency>
-
编写代码
import org.apache.spark.SparkConf import org.apache.spark.streaming.kafka.KafkaUtils import org.apache.spark.streaming.{Seconds, StreamingContext} import org.apache.spark.storage.StorageLevel import org.apache.spark.streaming.dstream.ReceiverInputDStream object Kafka2DStream { def main(args: Array[String]): Unit = { // 1. 连接kafka需要的⽤到的⼀些参数 val zookeeper = "hadoop101:2181,hadoop102:2181,hadoop103:2181" val group = "spark" val topic = "first" val numThreads = 3 // 2. 创建 StreamingContext val conf: SparkConf = new SparkConf().setAppName("Kafka2DStream").setMaster("local[*]") val streamingContext = new StreamingContext(conf, Seconds(5)) // 3. 创建 DStream val input: ReceiverInputDStream[(String, String)] = KafkaUtils.createStream(streamingContext, zookeeper, group, Map(topic -> numThreads), StorageLevel.MEMORY_ONLY) // 4. 对 KafkaStream操作 input.print() // 5. 启动 streamingContext.start() streamingContext.awaitTermination() } }