Spark Streaming(六):快取與持久化

weixin_34007291發表於2018-11-07

1、概述

與RDD類似,Spark Streaming也可以讓開發人員手動控制,將資料流中的資料持久化到記憶體中。
對DStream呼叫persist()方法,就可以讓Spark Streaming自動將該資料流中的所有產生的RDD,都持久化到記憶體中。
如果要對一個DStream多次執行操作,那麼,對DStream持久化是非常有用的。因為多次操作,可以共享使用記憶體中的一份快取資料。

對於基於視窗的操作,比如reduceByWindow、reduceByKeyAndWindow,以及基於狀態的操作,比如updateStateByKey,預設就隱式開啟了持久化機制。
即Spark Streaming預設就會將上述操作產生的Dstream中的資料,快取到記憶體中,不需要開發人員手動呼叫persist()方法。

對於通過網路接收資料的輸入流,比如socket、Kafka、Flume等,預設的持久化級別,是將資料複製一份,以便於容錯。
相當於是,用的是類似MEMORY_ONLY_SER_2。

與RDD不同的是,預設的持久化級別,統一都是要序列化的。

2、Checkpoint 機制

每一個Spark Streaming應用,正常來說,都是要7 * 24小時運轉的,這就是實時計算程式的特點。
因為要持續不斷的對資料進行計算,所以對實時計算應用的要求,應該是必須要能夠對與應用程式邏輯無關的失敗,進行容錯。

如果要實現這個目標,Spark Streaming程式就必須將足夠的資訊checkpoint到容錯的儲存系統上,從而讓它能夠從失敗中進行恢復。
有兩種資料需要被進行checkpoint:

  • 1、後設資料checkpoint——將定義了流式計算邏輯的資訊,儲存到容錯的儲存系統上,比如HDFS。當執行Spark Streaming應用程式的Driver程式所在節點失敗時,該資訊可以用於進行恢復。
    後設資料資訊包括了:

    • 1.1 配置資訊——建立Spark Streaming應用程式的配置資訊,比如SparkConf中的資訊。
    • 1.2 DStream的操作資訊——定義了Spark Stream應用程式的計算邏輯的DStream操作資訊。
    • 1.3 未處理的batch資訊——哪些job正在排隊,還沒處理的batch資訊。
  • 2、資料checkpoint——將實時計算過程中產生的RDD的資料儲存到可靠的儲存系統中。

    對於一些將多個batch的資料進行聚合的,有狀態的transformation操作,這是非常有用的。在這種transformation操作中,生成的RDD是依賴於之前的batch的RDD的,這會導致隨著時間的推移,RDD的依賴鏈條變得越來越長。

    要避免由於依賴鏈條越來越長,導致的一起變得越來越長的失敗恢復時間,有狀態的transformation操作執行過程中間產生的RDD,會定期地被checkpoint到可靠的儲存系統上,比如HDFS。從而削減RDD的依賴鏈條,進而縮短失敗恢復時,RDD的恢復時間。

一句話概括,後設資料checkpoint主要是為了從driver失敗中進行恢復;而RDD checkpoint主要是為了,使用到有狀態的transformation操作時,能夠在其生產出的資料丟失時,進行快速的失敗恢復。

3、啟用Checkpoint機制

  • 何時啟用Checkpoint機制
    • 1、使用了有狀態的transformation操作——比如updateStateByKey,或者reduceByKeyAndWindow操作,被使用了,那麼checkpoint目錄要求是必須提供的,也就是必須開啟checkpoint機制,從而進行週期性的RDD checkpoint。

    • 2、要保證可以從Driver失敗中進行恢復——後設資料checkpoint需要啟用,來進行這種情況的恢復。

要注意的是,並不是說,所有的Spark Streaming應用程式,都要啟用checkpoint機制,如果即不強制要求從Driver失敗中自動進行恢復,又沒使用有狀態的transformation操作,那麼就不需要啟用checkpoint。事實上,這麼做反而是有助於提升效能的。

  • 如何啟用Checkpoint機制
    • 1、對於有狀態的transformation操作,啟用checkpoint機制,定期將其生產的RDD資料checkpoint,是比較簡單的。

      可以通過配置一個容錯的、可靠的檔案系統(比如HDFS)的目錄,來啟用checkpoint機制,checkpoint資料就會寫入該目錄。使用StreamingContext的checkpoint()方法即可。然後,你就可以放心使用有狀態的transformation操作了。

    • 2、如果為了要從Driver失敗中進行恢復,那麼啟用checkpoint機制,是比較複雜的,需要改寫Spark Streaming應用程式。

      當應用程式第一次啟動的時候,需要建立一個新的StreamingContext,並且呼叫其start()方法,進行啟動。當Driver從失敗中恢復過來時,需要從checkpoint目錄中記錄的後設資料中,恢復出來一個StreamingContext。

    //為Driver失敗的恢復機制重寫程式
JavaStreamingContextFactory contextFactory = new JavaStreamingContextFactory() {
  @Override 
  public JavaStreamingContext create() {
    JavaStreamingContext jssc = new JavaStreamingContext(...);  
    JavaDStream<String> lines = jssc.socketTextStream(...);     
    jssc.checkpoint(checkpointDirectory);                       
    return jssc;
  }
};

JavaStreamingContext context = JavaStreamingContext.getOrCreate(checkpointDirectory, contextFactory);
context.start();
context.awaitTermination();
def functionToCreateContext(): StreamingContext = {
    val ssc = new StreamingContext(...)  
    val lines = ssc.socketTextStream(...) 
    ssc.checkpoint(checkpointDirectory)   
    ssc
}

val context = StreamingContext.getOrCreate(checkpointDirectory, functionToCreateContext _)
context.start()
context.awaitTermination()

4、配置spark-submit提交引數

按照上述方法,進行Spark Streaming應用程式的重寫後,當第一次執行程式時,如果發現checkpoint目錄不存在,那麼就使用定義的函式來第一次建立一個StreamingContext,並將其後設資料寫入checkpoint目錄;當從Driver失敗中恢復過來時,發現checkpoint目錄已經存在了,那麼會使用該目錄中的後設資料建立一個StreamingContext。

但是上面的重寫應用程式的過程,只是實現Driver失敗自動恢復的第一步。第二步是,必須確保Driver可以在失敗時,自動被重啟。

要能夠自動從Driver失敗中恢復過來,執行Spark Streaming應用程式的叢集,就必須監控Driver執行的過程,並且在它失敗時將它重啟。對於Spark自身的standalone模式,需要進行一些配置去supervise driver,在它失敗時將其重啟。

首先,要在spark-submit中,新增--deploy-mode引數,預設其值為client,即在提交應用的機器上啟動Driver;但是,要能夠自動重啟Driver,就必須將其值設定為cluster;此外,需要新增--supervise引數。

使用上述第二步驟提交應用之後,就可以讓driver在失敗時自動被重啟,並且通過checkpoint目錄的後設資料恢復StreamingContext。

5、補充說明

將RDD checkpoint到可靠的儲存系統上,會耗費很多效能。當RDD被checkpoint時,會導致這些batch的處理時間增加。因此,checkpoint的間隔,需要謹慎的設定。對於那些間隔很多的batch,比如1秒,如果還要執行checkpoint操作,則會大幅度削減吞吐量。而另外一方面,如果checkpoint操作執行的不太頻繁,那就會導致RDD的lineage變長,又會有失敗恢復時間過長的風險。

對於那些要求checkpoint的有狀態的transformation操作,預設的checkpoint間隔通常是batch間隔的數倍,至少是10秒。使用DStream的checkpoint()方法,可以設定這個DStream的checkpoint的間隔時長。
通常來說,將checkpoint間隔設定為視窗操作的滑動間隔的5~10倍,是個不錯的選擇。

相關文章