spark-17.sparkStreaming_2_DStream的輸入

1.文件數據源

監控目錄下新生成的文件,將文件內容讀成一個RDD,這個文件最好是mv進來的。

import org.apache.spark.streaming._
val ssc = new StreamingContext(sc,Seconds(5))
val lineDStream = ssc.textFileStream("hdfs://master:9000/data")
val words = lineDStream.flatMap(_.split(" "))
val word2count = words.map((_,1))
val result = word2count.reduceByKey(_+_)
result.print
ssc.start

2.RDD隊列

監控一個隊列,實時獲取隊列中的新增的RDD。

package com.dendan.queueRDD

import org.apache.spark.SparkConf
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.{Seconds, StreamingContext}

import scala.collection.mutable

object QueueRDD {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setMaster("local[*]").setAppName("QueueRDD")
    val ssc = new StreamingContext(conf, Seconds(1))

    //創建RDD隊列
    val rddQueue = new mutable.SynchronizedQueue[RDD[Int]]()
    //創建QueueInputDStream
    val inputStream = ssc.queueStream(rddQueue)
    //處理隊列中的RDD數據
    val mappedStream = inputStream.map(x => (x % 10, 1))
    val reducedStream = mappedStream.reduceByKey(_ + _)
    //打印結果
    reducedStream.print()
    //自動計算
    ssc.start()
    for (i <- 1 to 30) {
      rddQueue += ssc.sparkContext.makeRDD(1 to 300, 10)
      Thread.sleep(2000)
      //通過程序停止StreamingContext的運行
      //      ssc.stop()
    }

    ssc.awaitTermination()
  }
}

3.自定義Receiver

繼承Receiver抽象類,實現onStart和onStop方法。
使用:通過ssc.receiverStream傳入一個自定義的Receiver實例。

package com.dendan

import java.io.{BufferedReader, InputStreamReader}
import java.net.Socket
import java.nio.charset.StandardCharsets

import org.apache.spark.SparkConf
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.receiver.Receiver

/**
 * 自定義Receiver
 *
 * @param host
 * @param port
 */
class CustomReceiver(host: String, port: Int) extends Receiver[String](StorageLevel.MEMORY_ONLY) {
  /**
   * 程序啓動的時候調用
   */
  override def onStart(): Unit = {
    val socket = new Socket(host, port)
    var inputText = ""
    val reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8))
    inputText = reader.readLine()
    while (!isStopped() && inputText != null) {
      //如果接收到了數據就保存
      store(inputText)
      inputText = reader.readLine()
    }
    //重新連接,重新執行onStart()方法
    restart("")
  }

  /**
   * 程序停止的時候調用
   */
  override def onStop(): Unit = {}
}

object CustomReceiver {
  def main(args: Array[String]): Unit = {
    //創建配置
    val sparkConf = new SparkConf().setAppName("streaming").setMaster("local[*]")
    //創建streamingContext
    val ssc = new StreamingContext(sparkConf, Seconds(5))

    // 業務邏輯:從socket接受數據
    val lineDStream = ssc.receiverStream(new CustomReceiver("master", 9999))

    val wordStream = lineDStream.flatMap(_.split(" "))
    val word2CountDStream = wordStream.map((_, 1))
    val resultDStream = word2CountDStream.reduceByKey(_ + _)
    resultDStream.print()

    //啓動ssc
    ssc.start()
    ssc.awaitTermination()
  }
}

4.對接Kafka

在這裏插入圖片描述
連接kafka的兩種方式:

  • 通過kafka的高級API來獲取數據,這種情況是spark比較老的版本支持的情況,receiver運行再某一個executor中,性能比較低,會存在丟失數據的風險,spark爲了保存數據處理,提供了WAL(預寫日誌)的方式來保證。
  • 通過kafka的低級API來獲取數據,這種情況是spark比較新的版本提供的,性能比較高,receiver運行在Driver端,由於使用了低級API,需要業務人員手動維護offset,需要保證業務代碼的事務性。

連接池技術:
主要通過apache提供的commons-tools來實現在sparkstreaming寫入到kafka的時候,從連接池中獲取kafka連接。
連接的時候使用如下jar包:

<!-- streaming 與 kafka 連接-->
<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-streaming-kafka_2.11</artifactId>
    <version>1.6.3</version>
</dependency>
<!-- kafka連接池技術 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.5.0</version>
</dependency>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章