Spark Streaming重複消費,多次輸出問題剖析與解決方案

1,Exactly once 事務

什麼事Exactly once 事務?

數據僅處理一次並且僅輸出一次,這樣纔是完整的事務處理。

Spark在運行出錯時不能保證輸出也是事務級別的。在Task執行一半的時候出錯了,雖然在語義上做了事務處理,數據僅被處理一次,但是如果是輸出到數據庫中,那有空能將結果多次保存到數據庫中。Spark在任務失敗時會進行重試,這樣會導致結果多次保存到數據庫中。

如下圖,當運行在Executor上的Receiver接收到數據通過BlockManager寫入內存和磁盤,或者通過WAL機制寫記錄日誌,然後把metedata信息彙報給Driver。在Driver端定期進行checkpoint操作。Job的執行還是基於Spark Core的調度模式在Executor上執行Task。

Exactly once 事務的處理:

1,數據零丟失:必須有可靠的數據來源和可靠的Receiver,且整個應用程序的metadata必須進行checkpoint,且通過WAL來保證數據安全。

我們以數據來自Kafka爲例,運行在Executor上的Receiver在接收到來自Kafka的數據時會向Kafka發送ACK確認收到信息並讀取下一條信息,kafka會updateOffset來記錄Receiver接收到的偏移,這種方式保證了在Executor數據零丟失。

在Driver端,定期進行checkpoint操作,出錯時從Checkpoint的文件系統中把數據讀取進來進行恢復,內部會重新構建StreamingContext(也就是構建SparkContext)並啓動,恢復出元數據metedata,再次產生RDD,恢復的是上次的Job,然後再次提交到集羣執行。

那麼數據可能丟失的地方有哪些呢和相應的解決方式?

    在Receiver收到數據且通過Driver的調度Executor開始計算數據的時候,如果Driver突然奔潰,則此時Executor會被殺死,那麼Executor中的數據就會丟失(如果沒有進行WAL的操作)。

解決方式:此時就必須通過例如WAL的方式,讓所有的數據都通過例如HDFS的方式首先進行安全性容錯處理。此時如果Executor中的數據丟失的話,就可以通過WAL恢復回來。

這種方式的弊端是通過WAL的方式會極大額損傷SparkStreaming中Receivers接收數據的性能。

數據重複讀取的情況:

    在Receiver收到數據保存到HDFS等持久化引擎但是沒有來得及進行updateOffsets(以Kafka爲例),此時Receiver崩潰後重新啓動就會通過管理Kafka的Zookeeper中元數據再次重複讀取數據,但是此時SparkStreaming認爲是成功的,但是kafka認爲是失敗的(因爲沒有更新offset到ZooKeeper中),此時就會導致數據重新消費的情況。

    解決方式:以Receiver基於ZooKeeper的方式,當讀取數據時去訪問Kafka的元數據信息,在處理代碼中例如foreachRDD或transform時,將信息寫入到內存數據庫中(memorySet),在計算時讀取內存數據庫信息,判斷是否已處理過,如果以處理過則跳過計算。這些元數據信息可以保存到內存數據結構或者memsql,sqllite中。

 

如果通過Kafka作爲數據來源的話,Kafka中有數據,然後Receiver接收的時候又會有數據副本,這個時候其實是存儲資源的浪費。

Spark在1.3的時候爲了避免WAL的性能損失和實現Exactly Once而提供了Kafka Direct API,把Kafka作爲文件存儲系統。此時兼具有流的優勢和文件系統的優勢,至此Spark Streaming+Kafka就構建了完美的流處理世界(1,數據不需要拷貝副本;2,不需要WAL對性能的損耗;3,Kafka使用ZeroCopy比HDFS更高效)。所有的Executors通過Kafka API直接消息數據,直接管理Offset,所以也不會重複消費數據。

 

2,輸出不重複

關於Spark Streaming數據輸出多次重寫及其解決方案:

1,爲什麼會有這個問題,因爲Spark Streaming在計算的時候基於Spark Core天生會做以下事情導致Spark Streaming的結果(部分)重複輸出。Task重試,慢任務推測,Stage重試,Job重試。

2,具體解決方案:

設置spark.task.maxFailures次數爲1,這樣就不會有Task重試了。設置spark.speculation爲關閉狀態,就不會有慢任務推測了,因爲慢任務推測非常消耗性能,所以關閉後可以顯著提高Spark Streaming處理性能。

Spark Streaming On Kafka的話,Job失敗後可以設置Kafka的參數auto.offset.reset爲largest方式。

    最後再次強調可以通過transform和foreachRDD基於業務邏輯代碼進行邏輯控制來實現數據不重複消費和輸出不重複。這兩個方法類似於Spark Streaming的後門,可以做任意想象的控制操作。

文章出處:https://blog.csdn.net/yxhzj/article/details/79579998

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