Direct 方法(沒有Receiver)
一、概述
本方法是從Spark1.3版本引進的,提供更加強大的端到端的數據保障,改善數據丟失的情況,並且不再採用receiver的方式去接收數據,這方法週期性地從每一個topic分區裏面查詢kafka最近的偏移量(offsets),再週期性定義每個批次(batch)的offset的範圍,相當於拿到每一個批次的偏移量後,再直接通過kafka的api,去kafka裏面,把每個批次的offset的範圍給讀取出來直接操作,當啓動任務去處理這個數據,使用kafka的simple consumer API去從kafka裏讀取偏移量的範圍,這跟讀文件系統非常類似,這特性在Spark1.3裏面支持Java和Scala,在Spark1.4版本里支持Python。
二 、優點
相比於receiver方式,本方式的優點有下面幾點:
1.簡化了並行度。我們不需要創建多個Input Stream然後把它們聯合起來,而是直接使用direct stream進行處理;
2. 高性能。能達到0數據丟失。在第一種方式裏面,我們需要把數據寫到WAL裏面,以副本的方式寸尺數據才能保證無數據丟失,這不是一種高效的方法,而採用第二種方式,不用receiver讀取數據,不需要寫WAL;
3. 滿足只執行一次的語義。第一種方式是使用kafka的高級別的API在zookeeper裏面存儲offset,這是傳統的方式從kafka裏面消費數據,這會有小的機率造成數據丟失,這是由於SparkStream所接收的數據跟zookeeper所追蹤的數據可能會出現不一致。而第二種方式,採用簡單的kafka API,不使用zookeeper。Offset將被Spark Streaming 的checkpoints所追蹤,這樣就能消除Spark Streaming與 zookeeper/kafka的不一致的問題,因此,每條記錄都將被Spark Streaming進行有效準確地一次性接收(儘管有時也會失敗)。
注意:爲了使你的結果輸出滿足只執行一次的語義,你的輸出數據到其他數據存儲設備的操作必須是冪等的,即是重複執行多少次結果都是一樣的,或者採用事務的方式保存輸出結果和offset,保持其原子性。
三、缺點
無法更新偏移量到Zookeeper裏面去,使得基於zookeeper的kafka監控工具無法使用,需要自己週期性地把每個批次消費的offsets更新到zookeeper裏去。
四、整合步驟
1. 導入依賴
groupId = org.apache.spark
artifactId = spark-streaming-kafka-0-8_2.11
version = 2.2.0
2.編碼
引入KafkaUtils建DirectStream(注意與第一種方式的差別)
import org.apache.spark.streaming.kafka._
val directKafkaStream = KafkaUtils.createDirectStream[
[key class], [value class], [key decoder class], [value decoder class] ](
streamingContext, [map of Kafka parameters], [set of topics to consume])
Demo
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()
}
}
3.部署
步驟同方式一,spark-submit命令如下:
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
官網地址:http://spark.apache.org/docs/latest/streaming-kafka-0-8-integration.html