Spark Streaming 效能優化

weixin_34194087發表於2018-01-17

效能優化

為了獲得執行在叢集上的Spark應用的最好的效能需要一些調優。這一部分介紹了一些能夠改善應用效能的一些引數和配置。從更高的角度看,你需要考慮兩件事情:
1、高效的使用叢集的資源從而降低每個batch的資料處理的時間
2、設定合理的batch的大小從而資料使得資料處理的速度和接收速度一樣。

減少每個Batch的處理時間

為了減少每個batch的處理時間 是有許多可以優化操作,稍後 Tuning Guide
中有討論。這一節著重講述了比較重要的一些優化。

資料接收的並行度

通過網路接收到的資料需要資料在spark內進行反序列化和儲存。如果資料的接收變成了系統的瓶頸,就需要考慮並行處理資料的接收。需要注意的是,每個輸入流在worker的節點上建立了單獨的receiver,它只會接收一個流的資料。接收多個資料流的花需要通過建立多個資料流並且配置它們使得能夠接收輸入流的不同分割槽的資料。舉個例子,一個kafka的輸入DStream 接收兩個topic的資料可以其分成兩個stream,每個接收一個topic。這樣就會執行兩個receiver,這樣就會並行接收資料,因而提高了整體的吞吐量。多個DStream 可以union成一個DStream,然後之前應用於一個DStream的transformation 操作就可以應用於被unioned的DStream上了,操作入下:

val numStreams = 5
val kafkaStreams = (1 to numStreams).map { i => KafkaUtils.createStream(...) }
val unifiedStream = streamingContext.union(kafkaStreams)
unifiedStream.print()

另外一個需要考慮的就是 receiver的 block interval(區塊時長暫時翻譯),這個由引數configuration parameter spark.streaming.blockInterval 決定
接收多個資料流資料另外一個選擇是使用inputStream.repartition(<number of partitions>) 明確的切分輸入資料流。它會在資料處理之前,把接收到的多個batch的資料分發到叢集中的指定數量的機器上

資料處理的並行度

如果平行計算的task的數量不夠大的話,叢集的資源利用率是不高的。舉個例子,分散式的reduce操作,比如reduceByKey和reduceByKeyAndWindow,這個預設的並行度是引數 spark.default.parallelism 控制的。你可以作為引數傳入並行度或者配置這個引數來修改預設值。

資料的序列化

資料序列化的壓力可以通過優化序列化方式的方法解決降低。針對於streaming的情況,這裡有兩種型別的資料可以被序列化。

  • InputData:預設情況下,Receiver接收到的資料是儲存在executors的記憶體內的,儲存的級別是StorageLevel.MEMORY_AND_DISK_SER_2.也就是說,資料是被序列化成位元組以減少剛才的壓力。並且會被複制以防executor失敗。而且資料會優先儲存在記憶體,直到需要計算的資料在記憶體已經儲存不下的時候才會寫入到磁碟。這些序列化明顯過度耗費資源,reciiver必須反序列化接收到的資料並且重新序列化成spark序列化的方式。
  • Streaming操作產生的持久化的RDD streaming計算產生的RDD會被持久化在記憶體中,舉個例子,視窗操作會在記憶體中持久化這些資料以防資料需要多次被處理。當時不同於SparkCore預設的StorageLevel.MEMORY_ONLY,持久化的RDD是預設是按照StorageLevel.MEMORY_ONLY_SER進行持久化的。
    以上兩種情形,使用Kryo序列化會降低CPU和記憶體的過度使用。
    在某些特殊的情況下,比如spark不需要保持大量的資料,持久化資料使用反序列化後的物件不會導致過度的gc壓力,所以也是一種可行的辦法。舉個例子,如果你在使用一個幾秒的batch並且沒有window的操作,你可以顯示的設定storage的級別從而關閉序列化。這將會減少cpu因為序列化而導致的壓力,從而提升效能。

啟動的Task過多

如果每秒鐘啟動的task的數量非常高(比如,每秒50或者更多),那麼分發任務到slave上的壓力將會非常大,並且將會使得要想獲得ms級別的延遲變得很難。這種壓力可以通過如下的改變降低:
執行模式:執行Spark使用standalone 模式或者粗粒度的 Mesos模式task的啟動時間會優於使用細粒度的Mesos的模式 可以參考 Running on Mesos guide
這個改變可以減少每個batch的時間到幾百ms,從而是的亞秒級的batchsize變得可行。

設定正確的batch間隔

為了保證執行在叢集上的spark應用穩定,必須保證資料處理的速度要達到資料接收的速度。換句話說,每個batch處理資料的速度必須和產生的速度一致。是否能一致可以通過monitoring的web ui 上的處理時間看到。正常情況下,處理時間要小於間隔時間。
取決於streaming計算的天然特徵,對於固定資源的叢集,batch的間隔對於資料在應用中的保持率有重大影響。舉個例子,比如 WordCountNetwork,針對於特定的資料速率,系統可以支援每隔2s的單詞統計,但是卻不能支援500ms的。因此,batch的間隔時間需要設定成實際生產中需要保持的的期望的資料速率。
一個好方法就是 計算一個合適的batch的大小 去測試一 保守的batch間隔和一個比較低的資料速率。為了驗證系統是否能跟上資料的速率,你可以檢視每個處理過的batch的端到端的處理延遲。如果delay的時間和batch的大小差不很多,那麼系統就是穩定。否則的花,如果delay持續增加,意味著系統跟不上資料的速率從而變得不穩定。一旦你有兩個一個固定的配置,你就可以嘗試增加資料的速率或者減少batch的大小。需要注意的是,由於快取資料增加導致的記憶體增加是ok的,只要延遲時間降到一個很低的值。

相關文章