文章目錄
Structured Streaming 簡介
流式處理理的難點
- 數據複雜性
- 多種數據源
- 多種數據格式
- 數據清洗
- 設計與使用
- Low-level APIs(偏底層的API,對開發人員不友好), Map、Reduce等
- 與ML、批處理結合
- failover(容錯處理)
Structured Streaming特點
針對以上的問題,structured streaming 作出了對應的解決
- 豐富的數據源支持
- 多種數據源 kafka 等,也有其他數據源在第三方庫裏給出提供。
- 內建avro支持,schema信息
- 數據去重,event time (對數據進行清洗)
- 設計與使用
- high level apis,DataFrame
- 交互式查詢、在線ML
- exactly once 語義
工作原理
micro-batch 處理模式
- trigger
- one batch (只執行一次,一次性的batch job)
- fixed interval (固定的interval 來執行)
- default 不設置trigger的話有一個默認值(前一個mini batch 執行完會緊接着執行下一個mini batch)
- 生成mini batch job
- sql engine
- source->operation-sink
工作流程:設置完trigger 生成mini batch job ,每個mini batch job 中都會進行以下處理流程,
使用spark sql 底層的sql引擎,將DataFrame轉換爲Rdds ,從source端獲取數據,進行處理,sink端寫出到外部存儲。一個mini batch job結束之後下一個mini batch job 又以相同的方式生成Rdd,在source ->operation 在到sink 寫出。每個mini batch job之間呢不是獨立的需要有個state操作。如上圖t2時的mini batch job 需要獲取到t1 mini job 的 state 進行相關的更新。
continuous處理理模式
- Continuous trigger
- DataFrame->RDDs
- 各partition log running task
- source->operation->sink
工作流程:需要把trigger 設置成continuous trigger ,和micro-batch 中trigger 不同之處是,設置的checkpoint interval,每次把checkpoint 寫到可靠的外部存儲系統的trigger。
一個continuous 作業的處理過程是:
也是使用spark sql 底層的sql引擎,將DataFrame轉換成邏輯執行計劃,最後轉化成物理執行計劃,在轉化成Rdds。source就會不斷的從外部獲取數據,進行處理,最後通過sink寫出。
因爲spark 分佈式系統會把rdd分成很多partition,然後就會每個task執行partition。這裏會和micro的模式有個區別,task 是log running task ,執行完當前partition數據之後 不會結束。會不停的從source拉數據寫入sink。因爲這裏只有通過一次dataframe 到 rdd的轉換,後面直接是拿到這個rdd,之後進行source-operation-sink的操作。所以處理時延是非常低的可以達到亞秒級別,micro-batch的處理模式,會把一個作業分成mini-batch,所以整體來說還是一個批處理的job。所以處理時延是在秒級的。
exactly once - source
- Source get offset
- wal before execution
- sink commit
- 出錯、重啓後重新執行
理解:exactly once 語義,streaming execution 會從source 獲取到一個available offset,本次要處理的offset。source會通過offset 從input端拿到要處理的數據,通過處理 寫到sink端在寫出,會進行commit操作,streaming execution 會把這種commit 信息會記錄到hdfs系統。source也會把available offset也會被存儲到hdfs.每次處理前後都會把信息進行存儲,若這之間出錯,會進行重新執行。
exactly once - sink 容錯
- File sink
- 每個batch 寫入目錄
- 所有file寫入成功,file path 寫入 commit log中
- 部分失敗,重新寫入
解釋:source 實現可重複執行的,sink端要實現一個密等的操作才能實現exactly once的語義。
exactly once – state store 容錯
- 更新的數據被持久化到hdfs
- StatestoreCoordiator
- 控制executor 各個partition state store 操作
- 失敗重啓後恢復數據
Spark 2.4新特性
-
[SPARK-24662] Support the LIMIT operator for streams in Append or Complete
mode- 只支持complete/append模式
-
[SPARK-24565] Exposed the output rows of each microbatch as a DataFrame using foreachBatch
-
支持一些rdd操作:在線ML
-
output寫⼊多個location (支持rdd操作的sink,來彌補spark 不支持的外部數據源)
-
對於continuous作業,可以使用foreach方法進行操作。
-
-
[SPARK-24763] Remove redundant key data from value in streaming
aggregation (按照key聚合的數據,不僅在key中也在value,這裏加了個可選項,可以選擇value中是否含有對應key值) -
[SPARK-25399] Fixed a bug where reusing execution threads from continuous processing for microbatch streaming can result in a correctness issue(兩種模式是代碼兼容的,代碼可以相互轉換,但是之前有個bug,之前相互轉換的數據會有錯誤,所以這個進行了bug修復。)
-
[SPARK-24730] Support for choosing either the min or max watermark when there are multiple input streams in a query(可以在多個流中選擇最小的或者最大的watermark進行設置)
Stateful 操作
分類
- stateless操作
- 每個批次執行相互獨立
- stateful 操作
- spark 通過watermarking丟棄的數據 groupby/join/deduplication
- 用戶自定義去除舊的數據 mapGroupsWithState/flatMapGroupsWithState
groupby操作
- aggregation: df.groupBy().avg(“key”);
- aggregation: by event time df.groupBy(window(“timestamp”,“10mins”)).avg(“value”)
- Aggregation by both: df.groupBy(window($“timestamp”,“10 minutes”),“key”).count
stateful 操作問題
- 舊數據持續更新state
- state持續增長
spark 通過Watermarking 來解決上面兩個有可能撐爆內存的問題。 - 捕獲event time最大值
- next batch
- watermarker 裏的數據被聚合
- watermarker外的數據被丟棄
解釋:當前時間的event time是12點10分(作爲max event time),我們watermark 設置的是1分鐘,batch的時間也是1分鐘,當下一個event 過來的時候也就是是12點11分的時候,要是來的數據還屬於上一個批次的作業的時候呢,那麼這個數據將會被處理,要是更晚的event time到達的則會被丟棄。
官網例子:
watermarking 舉例
- 數據去重
userActions.withWatermark(“timestamp”,“10 seconds”).dropDuplicates(“uniqueRecordId”)
mapGroupsWithState/flatMapGroupsWithState(自己管理state的API)
- ⾃定義state數據類型
- 自定義state操作
- 自定義state 狀態管理
- timeout
- value=empty
- hasTimedOut=true
def mappingFunction(key: String, value: Iterator[Int], state: GroupState[Int]): String = { if (state.hasTimedOut) {
// 處理理超時 state.remove()
} else {
val existingState = state.getOption.getOrElse(new UserStatus()) val newState = existingState.handle(value) //業務處理理,更更新state state.update(newState)
state.setTimeoutDuration("1 hour")
}
// return something }
dataset.groupByKey(...) .mapGroupsWithState(GroupStateTimeout.ProcessingTimeTimeout)(mappingFunction)
continuous aggregation 操作
前面介紹的操作,都是micro-batch支持的操作,下面的操作數據continuous
- 處於實驗階段,不支持生產
- 只支持map filter 等操作
- 不支持聚合,如果要執行聚合,需要coalesce(1).
使用場景
週期行的處理最近的數據
- Trigger 設置成Once 只執行一次
- 處理上一個batch到最近的數據
- 週期性啓動job
低時延獲取數據更新
- stateful 操作
- 數據存儲kv數據庫,方便key查詢
結合維表
- join 數據合併
- 重啓作業獲取更新的數據
Change data capture
- 採集Mysql 數據導入 Hive
- binlog -> streaming -> delta
數據寫入多個表
- 多個query 流
- 解析一次,寫入中間表
- 讀取中間表,寫入數據表
- foreachBatch操作
- 解析一次,寫入多個數據表
- 沒有可靠行保證
SPARK+AI SUMMIT 2019 案例
- Streaming + Batch + SQL
Near Real-Time Analytics with Apache Spark: Ingestion, ETL, and Interactive Queries - NHSD
how australias national health services directory improved data quality reliability and integrity with databricks delta and structured streaming - Zalando
Continuous Applications at Scale of 100 Teams with Databricks Delta and Structured Streaming - PySpark API
writing continuous applications with structured streaming pyspark api