iT邦幫忙

2024 iThome 鐵人賽

DAY 20
1

昨天我們透過 Debezium + Kafka Connect 的搭配,我們把分別來自 Postgres 和 Mongo 的訂單 orders 和 顧客 users 每一次的資料變更都捕捉到訊息佇列 Kafka 了。但在此之後,離 RFM 分析即時報表,還有一段即時運算的距離未完成。

拿到即時資料後,我們可以從各種 Stream Processing 的框架中比較特性,挑選適合的工具:

  • Apache Spark Streaming:特色是處理 micro-batch 很強大,但對於 event-based 的即時需求而言,還是有著較高的延遲。
  • Apache Kafka Streams:專為 Kafka 生態系設計的 Stream Processing 函式庫,符合我們對即時性的需求,很可惜只支援 Java 和 Scala,沒有支援 Python 開發者。
  • Apache Flink:能夠處理大量的即時事件仍然維持低延遲。而且它支援 Python 與 SQL (Flink SQL),這真是一大福音!

看起來無懸念,延續我們先前使用 SQL 做資料轉換及利用 Python 撰寫 Airflow 做任務編排的技能樹,我們就選用 Flink 來做即時運算引擎啦!

Flink 簡介與特性


Flink 透過分散式框架,面對巨量資料仍然能維持高效率處理,包含高吞吐量 (throughput) 低延遲 (latency)。同時,它將Batch Processing 視為一種特化的 Streaming Processing,可理解成批量處理就是時間區間無限小的串流處理,因此可以透過同樣的運算機制 DataStream API 處理,達成所謂的批流合一。

精準一次 | Exactly-once

即使產製者 (producer) 重新嘗試發送訊息,也只會讓訊息傳送給消費者 (consumer) 一次。Flink 的這個特性非常重要,因為在我們的分析情境裡,沒辦法接受有些訂單變更可能被遺漏處理。也沒辦法接受重複收到訂單帶來的溢算後果。

狀態流 | Stateful Stream

狀態 (state) 表示執行單位 (operator) 在處理當下事件的時候,保持對先前事件的記憶。
有狀態操作 (stateful operation) 的一些範例:

  • 應用程式搜尋某些事件時,狀態將保存至今為止遇到的事件序列 (sequence)。
  • 定時 (分鐘/小時/天) 進行事件的 GROUP BY時,狀態將保存待處理的聚合 (aggregates) 。
  • 透過資料流訓練機器學習模型時,狀態會保存模型參數 (parameters) 的目前版本。

這些記憶是透過保存點 (checkpoint) 技術實現,它定期保存上述提到的狀態和資料進展。這樣當系統不幸故障時,可以從最近的保存點恢復,避免重新處理整個資料流。
狀態記憶會儲存到永久性的訊息佇列或檔案系統 (例如 HDFS、S3 等),當系統故障或重啟時,從可以從這些 checkpoint 繼續處理未完成的資料流,確保資料計算的一致性和準確性。

視窗機制|Window

https://ithelp.ithome.com.tw/upload/images/20241004/20168816fPxob1xhZd.png
Source: https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/dev/datastream/operators/windows/#window-lifecycle
像上圖的資料,視窗 (window) 是處理持續流入且沒有界線的資料流的核心概念。 Windows 將這種連續資料流分割成有限大小的桶子 (bucket) 後,就可以一一進行運算。

特色應用


讓我們回顧一下 RFM 分析的三個指標,其實都和 orders 有關,在批量計算時的 SQL 如下:

SELECT
    user_id,
    MAX(ordered_at) AS last_order_date,
    COUNT(order_id) AS order_count,
    SUM(order_amount) AS total_spent_amount
FROM
    `orders`
WHERE
    {time_filter: from start to now}
GROUP BY
    user_id
;

應用 Flink 在做 COUNTSUM 的聚合時,只要善用前一次狀態,把新進來的訂單金額和數量疊加上去就可以獲得正確的數量。但對於 MAX 的計算而言,則會需要找出整個資料流中的最大值。在持續運行時,必須保存每個分組的目前最大值。隨著資料規模增長,保存這些狀態的記憶體需求也會增加。
狀態的保存時間 (time-to-live, TTL) 可以根據商業應用情境調控,以避免狀態記憶量過大。例如:超過一定時間以前的訂單就不納入考慮。

小總結


以上特性讓 Flink 在處理即時資料流時,能在巨量資料湧入下仍具備一定的低延遲水準。同時透過視窗切割以及狀態保存點,確保計算結果的準確性以及故障復原的可靠性。

參考資料



上一篇
《資料與程式碼的交鋒》Day 19 - 資料異動即時串接
下一篇
《資料與程式碼的交鋒》Day 21 - 即時性的迷思
系列文
資料與程式碼的交鋒 - Data Engineer 與合作夥伴的協奏曲 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言