文章目錄
官方文檔:
http://spark.apache.org/docs/2.2.0/streaming-kafka-integration.html
Spark Streaming整合Kafka的版本選擇詳解
在spark2.2之前建議選擇spark-streaming-kafka-0-8版本;雖然spark-streaming-kafka-0-10是優化更好的;但是2.2之前的相關api還不穩定
在spark2.3之後建議選擇spark-streaming-kafka-0-10版本;spark-streaming-kafka-0-8已經是官方棄用的。
以下是基於spark2.2的測試:
Receiver方式整合之概述
這種方法使用一個接收器來接收數據。接收器是使用Kafka高級消費者API(高級api就是offset偏移量是自動完成控制;手動控制offset的就是低級api)實現的。與所有接收方一樣,通過接收方從Kafka接收到的數據存儲在Spark執行器中,然後由Spark流啓動的作業處理這些數據。
但是,在默認配置下,這種方法在失敗時可能會丟失數據(參見接收方可靠性)。爲了確保零數據丟失,您必須在Sparkstreaming中(在Spark 1.2中引入)另外啓用WAL機制。這將同步地將所有接收到的Kafka數據保存到分佈式文件系統(比如HDFS),以便在故障時可以恢復所有數據。有關寫前日誌的詳細信息,請參閱流編程指南中的部署部分。
Receiver方式整合之Kafka測試
Receiver整合前置條件:
- 啓動zk
- 啓動kafka
- 創建topic
- 通過控制檯測試本topic是否能夠正常的生產和消費信息
Receiver方式整合之Spark Streaming應用開發
添加pom文件中的依賴
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming-kafka-0-8_2.11</artifactId>
<version>${spark.version}</version>
</dependency>
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
/**
* Spark Streaming對接Kafka的方式一
*/
object KafkaReceiverWordCount {
def main(args: Array[String]): Unit = {
if(args.length != 4) {
System.err.println("Usage: KafkaReceiverWordCount <zkQuorum> <group> <topics> <numThreads>")
}
val Array(zkQuorum, group, topics, numThreads) = args
val sparkConf = new SparkConf() //.setAppName("KafkaReceiverWordCount")
//.setMaster("local[2]")
val ssc = new StreamingContext(sparkConf, Seconds(5))
val topicMap = topics.split(",").map((_, numThreads.toInt)).toMap
// TODO... Spark Streaming如何對接Kafka
val messages = KafkaUtils.createStream(ssc, zkQuorum, group,topicMap)
// TODO... 自己去測試爲什麼要取第二個
messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
ssc.start()
ssc.awaitTermination()
}
}
Receiver方式整合之本地環境聯調
1、啓動IDEA應用程序:
2、從kafka生產者端輸入消息
觀察本地IDEA控制檯可以看到計算結果
同時kafka消費端也有消息輸出
Receiver方式整合之服務器環境聯調及Streaming UI講解
1、將本地IDEA的應用程序打包:mvn clean package -DskipTests
2、將jar包上傳到spark服務器上
3、提交應用程序
spark-submit \
--class com.imooc.spark.KafkaReceiverWordCount \
--master local[2] \
--name KafkaReceiverWordCount \
--packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 \
/home/hadoop/lib/sparktrain-1.0.jar hadoop000:2181 test kafka_streaming_topic 1
4、向kafka輸入數據進行測試
Spark UI界面
下圖有一個receiver;如果停掉就沒有線程接受數據了。Directed模式不會有這個東西。
環境:
下圖界面對於調優有用。當前5s一個批次;運行了3分鐘11s
Direct方式整合之概述(推薦)
Spark 1.3中引入了這種新的無接收方“直接”方法,以確保更強的端到端保證。這種方法不使用接收者來接收數據,而是定期查詢Kafka以獲取每個主題+分區中的最新偏移量,並相應地定義每個批處理中的偏移量範圍。啓動處理數據的作業時,Kafka的簡單消費者API用於從Kafka讀取已定義的偏移量範圍(類似於從文件系統讀取文件)。請注意,這個特性是在針對Scala和Java API的Spark 1.3和針對Python API的Spark 1.4中引入的。
與基於接收者的方法(receive)相比,這種方法具有以下優點:
- 簡化並行性:不需要創建多個輸入Kafka流並將它們合併。使用directStream, Sparkstreaming將創建儘可能多的RDD分區,因爲有Kafka分區要使用,這些分區將並行地從Kafka讀取數據。因此Kafka和RDD分區之間存在一對一的映射,這更容易理解和優化。
- 效率:在receive方法中實現零數據丟失需要將數據存儲在WAL機制的日誌中,這樣可以進一步複製數據。這實際上是低效的,因爲數據被有效地複製了兩次——一次由Kafka複製,另一次由Write Ahead日誌複製。direct方法消除了這個問題,因爲沒有接收方,因此不需要提前寫日誌。只要保留了足夠的Kafka,就可以從Kafka恢復消息。
- 精確的一次性語義:receive方法使用Kafka的高級API在Zookeeper中存儲消耗的偏移量。這是傳統上使用Kafka數據的方式。雖然這種方法(與寫前日誌相結合)可以確保零數據丟失(即至少一次語義),但是在某些失敗情況下,一些記錄可能被使用兩次的可能性很小。這是因爲火花流可靠接收的數據與Zookeeper跟蹤的偏移量之間的不一致。因此,在direct種方法中,我們使用不使用Zookeeper的簡單Kafka API。偏移量通過其檢查點內的Spark流進行跟蹤。這消除了Sparkstreaming和Zookeeper/Kafka之間的不一致性,因此儘管出現了故障,Sparkstreaming仍然可以有效地接收每條記錄一次。爲了精確地實現結果輸出的一次性語義,將數據保存到外部數據存儲的輸出操作必須是冪等的,或者是保存結果和偏移量的原子事務(更多信息請參閱主編程指南中的輸出操作語義)。
注意,這種方法的一個缺點是它不更新Zookeeper中的偏移量,因此基於Zookeeper的Kafka監控工具不會顯示進度。但是,您可以在每個批處理中訪問這種方法處理的偏移量,並自己更新Zookeeper。
Direct方式整合之Spark Streaming應用開發及本地環境測試
import org.apache.spark.SparkConf
import org.apache.spark.streaming.kafka.KafkaUtils
import org.apache.spark.streaming.{Seconds, StreamingContext}
import kafka.serializer.StringDecoder
/**
* Spark Streaming對接Kafka的方式二
*/
object KafkaDirectWordCount {
def main(args: Array[String]): Unit = {
if(args.length != 2) {
System.err.println("Usage: KafkaDirectWordCount <brokers> <topics>")
System.exit(1)
}
val Array(brokers, topics) = args
val sparkConf = new SparkConf() //.setAppName("KafkaReceiverWordCount")
//.setMaster("local[2]")
val ssc = new StreamingContext(sparkConf, Seconds(5))
val topicsSet = topics.split(",").toSet
val kafkaParams = Map[String,String]("metadata.broker.list"-> brokers)
// TODO... Spark Streaming如何對接Kafka
val messages = KafkaUtils.createDirectStream[String,String,StringDecoder,StringDecoder](
ssc,kafkaParams,topicsSet
)
// TODO... 自己去測試爲什麼要取第二個
messages.map(_._2).flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
ssc.start()
ssc.awaitTermination()
}
}
運行
測試數據的方式和receive一樣。生產端輸入數據;查看本地IDEA控制檯。
Direct方式整合之服務器環境聯調
1、將本地IDEA的應用程序打包:mvn clean package -DskipTests
2、將jar包上傳到spark服務器上
3、提交應用程序
spark-submit \
--class com.imooc.spark.KafkaDirectWordCount \
--master local[2] \
--name KafkaDirectWordCount \
--packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 \
/home/hadoop/lib/sparktrain-1.0.jar hadoop000:9092 kafka_streaming_topic
查看UI界面發現沒有receive這個東西了
輸入一些測試數據;同時查看其他UI界面。