Spark 2.0 Structured Streaming 分析

前言

Spark 2.0 將流式計算也統一到DataFrame里去了,提出了Structured Streaming的概念,將數據源映射為一張無線長度的表,同時將流式計算的結果映射為另外一張表,完全以結構化的方式去操作流式數據,復用了其對象的Catalyst引擎。

Spark 2.0 之前

作為Spark平臺的流式實現,Spark Streaming 是有單獨一套抽象和API的,大體如下

圖片來源于Spakr官網

代碼的形態如下:

val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
//構建StreamingContext
val ssc = new StreamingContext(conf, Seconds(1))

//獲取輸入源
val lines = ssc.socketTextStream("localhost", 9999)

//邏輯計算
val wordCounts = lines.flatMap(_.split(" ")).
map(word => (word, 1)).
reduceByKey(_ + _)

wordCounts.print()

//啟動流式計算
ssc.start()         
ssc.awaitTermination() 

上面都是套路,基本都得照著這么寫。

Spark 2.0 時代

概念上,所謂流式,無非就是無限大的表,官方給出的圖一目了然:

圖片來源于官網

在之前的宣傳PPT里,有類似的代碼,給人煥然一新的感覺。當然,下面的代碼你肯定要有上下文的,就這一句肯定跑不起來的。

圖片來源于http://litaotao.github.io/images/spark-2.0-7.png

第一個是標準的DataFrame的使用代碼。下面第二個則是流式計算的代碼,看完這個demo你肯定會納悶:

  1. 沒有定時器么,我怎么設置duration?
  2. 在哪里設置awaitTermination呢?
  3. 如果我要寫入到其他引擎,而其他引擎沒有適配咋辦?

這些疑問其實歸結起來就是:

Structured Streaming 的完整套路是啥?

我們來看看代碼(例子來源于Spark源碼,我稍微做了些修改):

val spark = SparkSession  .builder  .
master("local[2]")  .
appName("StructuredNetworkWordCount").
getOrCreate()


 val schemaExp = StructType(
      StructField("name", StringType, false) ::
        StructField("city", StringType, true)
        :: Nil
    )

//標準的DataSource API,只不過read變成了readStream
   val words = spark.readStream.format("json").schema(schemaExp)
      .load("file:///tmp/dir")

   // DataFrame 的一些API
    val wordCounts = words.groupBy("name").count()

    //標準的DataSource 寫入 API,只不過write變成了writeStream
    val query = wordCounts.writeStream
//complete,append,update。目前只
//支持前面兩種
      .outputMode("complete") 
//console,parquet,memory,foreach 四種
      .format("console")
      .trigger(ProcessingTime(5.seconds))//這里就是設置定時器了
      .start()

    query.awaitTermination()

這個就是Structured Streaming 的完整套路了。

Structured Streaming 目前Source源只支持File 和 Socket 兩種。輸出則是四種,前面已經提到。foreach則是可以無限擴展的。我舉個例子:

val query = wordCounts.writeStream.trigger(ProcessingTime(5.seconds))
      .outputMode("complete")
      .foreach(new ForeachWriter[Row] {

      var fileWriter: FileWriter = _

      override def process(value: Row): Unit = {
        fileWriter.append(value.toSeq.mkString(","))
      }

      override def close(errorOrNull: Throwable): Unit = {
        fileWriter.close()
      }

      override def open(partitionId: Long, version: Long): Boolean = {
        FileUtils.forceMkdir(new File(s"/tmp/example/${partitionId}"))
        fileWriter = new FileWriter(new File(s"/tmp/example/${partitionId}/temp"))
        true
      }
    }).start()

我把數據最后寫到各個節點的臨時目錄里。當然,這只是個例子,不過其他類似于寫入Redis的,則是類似的。

Structured Streaming 不僅僅在于API的變化

如果Structured Streaming 僅僅是換個API,或者能夠支持DataFrame操作,那么我只能感到遺憾了,因為2.0之前通過某些封裝也能夠很好的支持DataFrame的操作。那么 Structured Streaming 的意義到底何在?

  • 重新抽象了流式計算
  • 易于實現數據的exactly-once

我們知道,2.0之前的Spark Streaming 只能做到at-least once,框架層次很難幫你做到exactly-once,參考我以前寫的文章Spark Streaming Crash 如何保證Exactly Once Semantics。 現在通過重新設計了流式計算框架,使得實現exactly-once 變得容易了。

可能你會注意到,在Structured Streaming 里,多出了outputMode,現在有complete,append,update 三種,現在的版本只實現了前面兩種。

  1. complete,每次計算完成后,你都能拿到全量的計算結果。
  2. append,每次計算完成后,你能拿到增量的計算結果。

但是,這里有個但是,使用了聚合類函數才能用complete模式,只是簡單的使用了map,filter等才能使用append模式。 不知道大家明白了這里的含義么?

complete 就是我們前面提到的mapWithState實現。 append 模式則是標準的對數據做解析處理,不做復雜聚合統計功能。

官方給出了complete 模式的圖:

圖片來源于官網

append 模式則是返回transform后最新的數據。

前面我們說到,現在的設計很簡單,其實就是 無限大的 Source Table 映射到一張無限大的 Result Table上,每個周期完成后,都會更新Result Table。我們看到,Structured Streaming 已經接管了端到端了,可以通過內部機制保證數據的完整性,可靠性。

  • offset 概念,流式計算一定有offset的概念。
  • 對于無法回溯的數據源則采用了WAL日志
  • state概念,對result table 的每個分區都進行狀態包裝,分區的的每個ADD,PUT,UPDATE,DELETE操作,都會寫入到HDFS上,方便系統恢復。

其中第三點是只有在2.0才有的概念。不過比較遺憾的是,result table 和ForeachWriter 并沒有什么結合,系統只是保證result table的完整性,通過HDFSBackedStateStoreProvider將result table 保存到HDFS。

以前的API就是給你個partition的iterator,你愛怎么玩怎么玩,但是到了現在,以ForeachWriter為例,

override def process(value: Row): Unit = {

數據你只能一條一條處理了。理論上如果假設正好在process的過程中,系統掛掉了,那么數據就會丟了,但因為 Structured Streaming 如果是complete模式,因為是全量數據,所以其實做好覆蓋就行,也就說是冪等的。

如果是append 模式,則可能只能保證at-least once ,而對于其內部,也就是result table 是可以保證exactly-once 的。對于比如數據庫,本身是可以支持事物的,可以在foreachWrite close的時候commit下,有任何失敗的時候則在close的時候,rollback 就行。但是對于其他的,比如HBase,Redis 則較為困難。

另外在ForeachWriter提供的初始化函數,

override def open(partitionId: Long, version: Long): Boolean = {

返回值是Boolean,通過檢測版本號,是否跳過這個分區的數據處理。返回true是為不跳過,否則為跳過。當你打開的時候,可以通過某種手段保存version,再系統恢復的時候,則可以讀取該版本號,低于該版本的則返回false,當前的則繼續處理。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容