kafka整合sparkStreaming問題

  • (1)、如何實現sparkStreaming讀取kafka中的數據

    • 可以這樣說:在kafka0.10版本之前有二種方式與sparkStreaming整合,一種是基於receiver,一種是direct,然後分別闡述這2種方式分別是什麼

      • receiver:是採用了kafka高級api,利用receiver接收器來接受kafka topic中的數據,從kafka接收來的數據會存儲在spark的executor中,之後spark streaming提交的job會處理這些數據,kafka中topic的偏移量是保存在zk中的。

        • 基本使用: val kafkaStream = KafkaUtils.createStream(streamingContext, [ZK quorum], [consumer group id], [per-topic number of Kafka partitions to consume])

        • 還有幾個需要注意的點:

          • 在Receiver的方式中,Spark中的partition和kafka中的partition並不是相關的,所以如果我們加大每個topic的partition數量,僅僅是增加線程來處理由單一Receiver消費的主題。但是這並沒有增加Spark在處理數據上的並行度.

          • 對於不同的Group和topic我們可以使用多個Receiver創建不同的Dstream來並行接收數據,之後可以利用union來統一成一個Dstream。

          • 在默認配置下,這種方式可能會因爲底層的失敗而丟失數據. 因爲receiver一直在接收數據,在其已經通知zookeeper數據接收完成但是還沒有處理的時候,executor突然掛掉(或是driver掛掉通知executor關閉),緩存在其中的數據就會丟失. 如果希望做到高可靠, 讓數據零丟失,如果我們啓用了Write Ahead Logs(spark.streaming.receiver.writeAheadLog.enable=true)該機制會同步地將接收到的Kafka數據寫入分佈式文件系統(比如HDFS)上的預寫日誌中. 所以, 即使底層節點出現了失敗, 也可以使用預寫日誌中的數據進行恢復. 複製到文件系統如HDFS,那麼storage level需要設置成 StorageLevel.MEMORY_AND_DISK_SER,也就是KafkaUtils.createStream(..., StorageLevel.MEMORY_AND_DISK_SER)

      • direct:在spark1.3之後,引入了Direct方式。不同於Receiver的方式,Direct方式沒有receiver這一層,其會週期性的獲取Kafka中每個topic的每個partition中的最新offsets,之後根據設定的maxRatePerPartition來處理每個batch。(設置spark.streaming.kafka.maxRatePerPartition=10000。限制每秒鐘從topic的每個partition最多消費的消息條數)。

  • (2) 對比這2中方式的優缺點:

    • 採用receiver方式:這種方式可以保證數據不丟失,但是無法保證數據只被處理一次,WAL實現的是At-least-once語義(至少被處理一次),如果在寫入到外部存儲的數據還沒有將offset更新到zookeeper就掛掉,這些數據將會被反覆消費. 同時,降低了程序的吞吐量。

    • 採用direct方式:相比Receiver模式而言能夠確保機制更加健壯. 區別於使用Receiver來被動接收數據, Direct模式會週期性地主動查詢Kafka, 來獲得每個topic+partition的最新的offset, 從而定義每個batch的offset的範圍. 當處理數據的job啓動時, 就會使用Kafka的簡單consumer api來獲取Kafka指定offset範圍的數據。

      • 優點:

        • 1、簡化並行讀取

          • 如果要讀取多個partition, 不需要創建多個輸入DStream然後對它們進行union操作. Spark會創建跟Kafka partition一樣多的RDD partition, 並且會並行從Kafka中讀取數據. 所以在Kafka partition和RDD partition之間, 有一個一對一的映射關係.

        • 2、高性能

          • 如果要保證零數據丟失, 在基於receiver的方式中, 需要開啓WAL機制. 這種方式其實效率低下, 因爲數據實際上被複制了兩份, Kafka自己本身就有高可靠的機制, 會對數據複製一份, 而這裏又會複製一份到WAL中. 而基於direct的方式, 不依賴Receiver, 不需要開啓WAL機制, 只要Kafka中作了數據的複製, 那麼就可以通過Kafka的副本進行恢復.

        • 3、一次且僅一次的事務機制

          • 基於receiver的方式, 是使用Kafka的高階API來在ZooKeeper中保存消費過的offset的. 這是消費Kafka數據的傳統方式. 這種方式配合着WAL機制可以保證數據零丟失的高可靠性, 但是卻無法保證數據被處理一次且僅一次, 可能會處理兩次. 因爲Spark和ZooKeeper之間可能是不同步的. 基於direct的方式, 使用kafka的簡單api, Spark Streaming自己就負責追蹤消費的offset, 並保存在checkpoint中. Spark自己一定是同步的, 因此可以保證數據是消費一次且僅消費一次。不過需要自己完成將offset寫入zk的過程,在官方文檔中都有相應介紹.*簡單代碼實例:

            * messages.foreachRDD(rdd=>{   

            val message = rdd.map(.2)//對數據進行一些操作 message.map(method)//更新zk上的offset (自己實現) updateZKOffsets(rdd)

            })
            * sparkStreaming程序自己消費完成後,自己主動去更新zk上面的偏移量。也可以將zk中的偏移量保存在mysql或者redis數據庫中,下次重啓的時候,直接讀取mysql或者redis中的偏移量,獲取到上次消費的偏移量,接着讀取數據。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章