Spark Streaming和Kafka整合開發指南(一)

五柳-先生發表於2015-12-09

Apache Kafka是一個分散式的訊息釋出-訂閱系統。可以說,任何實時大資料處理工具缺少與Kafka整合都是不完整的。本文將介紹如何使用Spark Streaming從Kafka中接收資料,這裡將會介紹兩種方法:(1)、使用Receivers和Kafka高層次的API;(2)、使用Direct API,這是使用低層次的KafkaAPI,並沒有使用到Receivers,是Spark 1.3.0中開始引入的。這兩種方法有不同的程式設計模型,效能特點和語義擔保。下文將會一一介紹。

基於Receivers的方法

  這個方法使用了Receivers來接收資料。Receivers的實現使用到Kafka高層次的消費者API。對於所有的Receivers,接收到的資料將會儲存在Spark executors中,然後由Spark Streaming啟動的Job來處理這些資料。

  然而,在預設的配置下,這種方法在失敗的情況下會丟失資料,為了保證零資料丟失,你可以在Spark Streaming中使用WAL日誌,這是在Spark 1.2.0才引入的功能,這使得我們可以將接收到的資料儲存到WAL中(WAL日誌可以儲存在HDFS上),所以在失敗的時候,我們可以從WAL中恢復,而不至於丟失資料。

  下面,我將介紹如何使用這種方法來接收資料。

  1、引入依賴。

  對於Scala和Java專案,你可以在你的pom.xml檔案引入以下依賴:

1 <dependency>
2   <groupId>org.apache.spark</groupId>
3   <artifactId>spark-streaming-kafka_2.10</artifactId>
4   <version>1.3.0</version>
5 </dependency>

  如果你是使用SBT,可以這麼引入:

1 libraryDependencies += "org.apache.spark" "spark-streaming-kafka_2.10" "1.3.0"

  2、程式設計

  在Streaming程式中,引入KafkaUtils,並建立一個輸入DStream:

1 import org.apache.spark.streaming.kafka._
2  
3 val kafkaStream =KafkaUtils.createStream(streamingContext,
4     [ZK quorum], [consumer group id], [per-topic number of Kafka partitions to consume])

  在建立DStream的時候,你也可以指定資料的Key和Value型別,並指定相應的解碼類。

  需要注意的是:
  1、Kafka中Topic的分割槽和Spark Streaming生成的RDD中分割槽不是一個概念。所以,在KafkaUtils.createStream()增加特定主題分割槽數僅僅是增加一個receiver中消費Topic的執行緒數。並不增加Spark並行處理資料的數量;

  2、對於不同的Group和tpoic我們可以使用多個receivers建立不同的DStreams來並行接收資料;

  3、如果你啟用了WAL,這些接收到的資料將會被持久化到日誌中,因此,我們需要將storage level 設定為StorageLevel.MEMORY_AND_DISK_SER ,也就是:

1 KafkaUtils.createStream(..., StorageLevel.MEMORY_AND_DISK_SER)

  3、部署

  對應任何的Spark 應用,我們都是用spark-submit來啟動你的應用程式,對於Scala和Java使用者,如果你使用的是SBT或者是Maven,你可以將spark-streaming-kafka_2.10及其依賴打包進應用程式的Jar檔案中,並確保spark-core_2.10和 spark-streaming_2.10標記為provided,因為它們在Spark 安裝包中已經存在:

01 <dependency>
02           <groupId>org.apache.spark</groupId>
03           <artifactId>spark-streaming_2.10</artifactId>
04           <version>1.3.0</version>
05           <scope>provided</scope>
06 </dependency>
07  
08 <dependency>
09           <groupId>org.apache.spark</groupId>
10           <artifactId>spark-core_2.10</artifactId>
11           <version>1.3.0</version>
12           <scope>provided</scope>
13 </dependency>

然後使用spark-submit來啟動你的應用程式。

  當然,你也可以不在應用程式Jar檔案中打包spark-streaming-kafka_2.10及其依賴,我們可以在spark-submit後面加上--jars引數也可以執行你的程式:

1 [iteblog@ spark]$ spark-1.3.0-bin-2.6.0/bin/spark-submit  --master yarn-cluster
2     --class iteblog.KafkaTest 
3     --jars lib/spark-streaming-kafka_2.10-1.3.0.jar,
4     lib/spark-streaming_2.10-1.3.0.jar,
5     lib/kafka_2.10-0.8.1.1.jar,lib/zkclient-0.3.jar,
6     lib/metrics-core-2.2.0.jar ./iteblog-1.0-SNAPSHOT.jar

下面是一個完整的例子:

01 object KafkaWordCount {
02   def main(args: Array[String]) {
03     if (args.length < 4) {
04       System.err.println("Usage: KafkaWordCount <zkQuorum> <group> <topics> <numThreads>")
05       System.exit(1)
06     }
07  
08     StreamingExamples.setStreamingLogLevels()
09  
10     val Array(zkQuorum, group, topics, numThreads) = args
11     val sparkConf = new SparkConf().setAppName("KafkaWordCount")
12     val ssc =  new StreamingContext(sparkConf, Seconds(2))
13     ssc.checkpoint("checkpoint")
14  
15     val topicMap = topics.split(",").map((_,numThreads.toInt)).toMap
16     val lines = KafkaUtils.createStream(ssc, zkQuorum, group, topicMap).map(_._2)
17     val words = lines.flatMap(_.split(" "))
18     val wordCounts = words.map(x => (x, 1L))
19       .reduceByKeyAndWindow(_ __ _, Minutes(10), Seconds(2), 2)
20     wordCounts.print()
21  
22     ssc.start()
23     ssc.awaitTermination()
24   }

25 }
尊重原創,轉載請註明: 轉載自過往記憶(http://www.iteblog.com/)
本文連結地址: 《Spark Streaming和Kafka整合開發指南(一)》(http://www.iteblog.com/archives/1322)

相關文章