Spark Streaming和Kafka整合是如何保證資料零丟失

五柳-先生發表於2016-03-03

當我們正確地部署好Spark Streaming,我們就可以使用Spark Streaming提供的零資料丟失機制。為了體驗這個關鍵的特性,你需要滿足以下幾個先決條件:

  1、輸入的資料來自可靠的資料來源和可靠的接收器;
  2、應用程式的metadata被application的driver持久化了(checkpointed );
  3、啟用了WAL特性(Write ahead log)。

  下面我將簡單地介紹這些先決條件。

可靠的資料來源和可靠的接收器

  對於一些輸入資料來源(比如Kafka),Spark Streaming可以對已經接收的資料進行確認。輸入的資料首先被接收器(receivers )所接收,然後儲存到Spark中(預設情況下,資料儲存到2個執行器中以便進行容錯)。資料一旦儲存到Spark中,接收器可以對它進行確認(比如,如果消費Kafka裡面的資料時可以更新Zookeeper裡面的偏移量)。這種機制保證了在接收器突然掛掉的情況下也不會丟失資料:因為資料雖然被接收,但是沒有被持久化的情況下是不會傳送確認訊息的。所以在接收器恢復的時候,資料可以被原端重新傳送。

後設資料持久化(Metadata checkpointing)

  可靠的資料來源和接收器可以讓我們從接收器掛掉的情況下恢復(或者是接收器執行的Exectuor和伺服器掛掉都可以)。但是更棘手的問題是,如果Driver掛掉如何恢復?對此開發者們引入了很多技術來讓Driver從失敗中恢復。其中一個就是對應用程式的後設資料進行Checkpint。利用這個特性,Driver可以將應用程式的重要後設資料持久化到可靠的儲存中,比如HDFS、S3;然後Driver可以利用這些持久化的資料進行恢復。後設資料包括:
  1、配置;
  2、程式碼;
  3、那些在佇列中還沒有處理的batch(僅僅儲存後設資料,而不是這些batch中的資料)

  由於有了後設資料的Checkpint,所以Driver可以利用他們重構應用程式,而且可以計算出Driver掛掉的時候應用程式執行到什麼位置。

可能存在資料丟失的場景

  令人驚訝的是,即使是可靠的資料來源、可靠的接收器和對後設資料進行Checkpint,仍然不足以阻止潛在的資料丟失。我們可以想象出以下的糟糕場景:

  1、兩個Exectuor已經從接收器中接收到輸入資料,並將它快取到Exectuor的記憶體中;
  2、接收器通知輸入源資料已經接收;
  3、Exectuor根據應用程式的程式碼開始處理已經快取的資料;
  4、這時候Driver突然掛掉了;
  5、從設計的角度看,一旦Driver掛掉之後,它維護的Exectuor也將全部被kill;
  6、既然所有的Exectuor被kill了,所以快取到它們記憶體中的資料也將被丟失。結果,這些已經通知資料來源但是還沒有處理的快取資料就丟失了;
  7、快取的時候不可能恢復,因為它們是快取在Exectuor的記憶體中,所以資料被丟失了。

這對於很多關鍵型的應用程式來說非常的糟糕,不是嗎?

WAL(Write ahead log)

  為了解決上面提到的糟糕場景,Spark Streaming 1.2開始引入了WAL機制。

  啟用了WAL機制,所以已經接收的資料被接收器寫入到容錯儲存中,比如HDFS或者S3。由於採用了WAl機制,Driver可以從失敗的點重新讀取資料,即使Exectuor中記憶體的資料已經丟失了。在這個簡單的方法下,Spark Streaming提供了一種即使是Driver掛掉也可以避免資料丟失的機制。

At-least-once語義

  雖然WAL可以確保資料不丟失,它並不能對所有的資料來源保證exactly-once語義。想象一下可能發生在Spark Streaming整合Kafka的糟糕場景。

  1、接收器接收到輸入資料,並把它儲存到WAL中;
  2、接收器在更新Zookeeper中Kafka的偏移量之前突然掛掉了;

  3、Spark Streaming假設輸入資料已成功收到(因為它已經寫入到WAL中),然而Kafka認為資料被沒有被消費,因為相應的偏移量並沒有在Zookeeper中更新;
  4、過了一會,接收器從失敗中恢復;
  5、那些被儲存到WAL中但未被處理的資料被重新讀取;
  6、一旦從WAL中讀取所有的資料之後,接收器開始從Kafka中消費資料。因為接收器是採用Kafka的High-Level Consumer API實現的,它開始從Zookeeper當前記錄的偏移量開始讀取資料,但是因為接收器掛掉的時候偏移量並沒有更新到Zookeeper中,所有有一些資料被處理了2次。

WAL的缺點

  除了上面描述的場景,WAL還有其他兩個不可忽略的缺點:

  1、WAL減少了接收器的吞吐量,因為接受到的資料必須儲存到可靠的分散式檔案系統中。
  2、對於一些輸入源來說,它會重複相同的資料。比如當從Kafka中讀取資料,你需要在Kafka的brokers中儲存一份資料,而且你還得在Spark Streaming中儲存一份。

Kafka direct API

  為了解決由WAL引入的效能損失,並且保證 exactly-once 語義,Spark Streaming 1.3中引入了名為Kafka direct API。
  這個想法對於這個特性是非常明智的。Spark driver只需要簡單地計算下一個batch需要處理Kafka中偏移量的範圍,然後命令Spark Exectuor直接從Kafka相應Topic的分割槽中消費資料。換句話說,這種方法把Kafka當作成一個檔案系統,然後像讀檔案一樣來消費Topic中的資料。

在這個簡單但強大的設計中:
  1、不再需要Kafka接收器,Exectuor直接採用Simple Consumer API從Kafka中消費資料。
  2、不再需要WAL機制,我們仍然可以從失敗恢復之後從Kafka中重新消費資料;
  3、exactly-once語義得以儲存,我們不再從WAL中讀取重複的資料。

  本文翻譯至:Recent Evolution of Zero Data Loss Guarantee in Spark Streaming With Kafka:http://getindata.com/blog/post/recent-evolution-of-zero-data-loss-guarantee-in-spark-streaming-with-kafka/
本部落格文章除特別宣告,全部都是原創!
尊重原創,轉載請註明: 轉載自過往記憶(http://www.iteblog.com/)
本文連結: 【Spark Streaming和Kafka整合是如何保證資料零丟失】(http://www.iteblog.com/archives/1591)

相關文章