批次處理跑在有界 (bounded) 的固定資料集上;串流處理跑在無界 (unbounded)、永遠不會結束的事件流上。難點不在「逐筆處理」,而在時間怎麼算、視窗怎麼切、遲到的事件怎麼辦。
🧠 Intuition
TIP
把它想成「永遠跑不完的批次作業」。輸入永遠在增加,所以你無法等資料「到齊」才算結果——只能在不完整的資料上持續產出、並準備好被後來的事件修正。
- 串流的基本單位是 event:一筆不可變、帶時間戳的小紀錄(一次點擊、一筆交易)。
- 事件由 producer 寫入、由多個 consumer 讀取,中間靠 message broker 解耦。
- 因為輸入無界,幾乎所有聚合都要先用 window 把無限的流切成有限的桶,才算得出結果。
⚖️ Tradeoffs
Log-based broker (Kafka) vs 傳統 AMQP/JMS
- 傳統 message queue(RabbitMQ、ActiveMQ):訊息被消費後即刪除,broker 記錄「誰確認了哪則」,適合 task queue 式的工作分派。
- log-based broker(Kafka、Pulsar):訊息持久化成 append-only log,consumer 各自維護 offset,可重放歷史、可多組獨立消費。
- 取捨:log-based 容易重播與多訂閱、吞吐高,但「單則訊息處理很慢」的場景不如 AMQP 那種逐則 ack 來得靈活(一則卡住會擋住整個 partition)。
- 經驗法則:要事件溯源 / 多下游 / 可重放選 log-based;要任務分派 / 優先序 / 逐則重試選傳統佇列。
事件時間 (Event time) vs 處理時間 (Processing time)
- event time:事件實際發生的時間(裝置上打的戳)。processing time:事件被系統處理的時間。
- 兩者會分歧:網路延遲、裝置離線後補傳、consumer 重啟追進度,都會讓事件「遲到」。
- 用 processing time 算視窗最簡單但會說謊:一次 consumer 卡頓就會讓某分鐘的計數暴增(其實是補算)。
- 正確做法用 event time,但代價是你永遠不確定某個視窗的事件是否到齊——這就是 watermark 要解的問題。
視窗類型 (Windowing)
- Tumbling:固定長度、不重疊(每 1 分鐘一桶)。每個事件只落在一個視窗。
- Hopping:固定長度但有固定步長、會重疊(長 5 分鐘、每 1 分鐘滑一次)——同一事件落在多個視窗,常用於滑動平均。
- Sliding:以每個事件為中心、看「前後 N 時間內」的其他事件,邊界由事件本身觸發。
- Session:沒有固定長度,用「不活動間隔 (gap)」切分——一連串密集事件算一個 session,靜默超過閾值就關窗。適合使用者行為分析。
Watermark 與遲到事件
- watermark 是一個推進中的斷言:「event time 早於 t 的事件,我認為都到齊了」——於是可以關閉 ≤ t 的視窗、輸出結果。
- 取捨永遠在延遲 vs 完整:watermark 推得快→結果出得早但容易漏掉遲到者;推得慢→結果更完整但延遲高。
- 遲到事件(晚於 watermark 才到)的處理策略:直接丟棄、或保留視窗狀態一段 grace period 後發修正值 (retraction/update)。
- 沒有完美解:分散式時鐘下「資料到齊」本質上不可知,只能用啟發式逼近。
Stream–stream join vs Stream–table join
- stream–stream join(如點擊流 join 曝光流):兩邊都是流,必須在時間視窗內配對,且要為兩邊維護狀態緩衝——狀態大、要設過期。
- stream–table join(流 enrich 一張維度表):用事件去查一張會變動的表(如 user id → profile)。表本身常是另一條 CDC 流重建的物化狀態。
- 關鍵陷阱:join 的結果取決於你用了哪個時刻的表狀態。維度表後來改了,重放同一段流會得到不同結果——這就是為什麼要把表也當成「帶時間的變更流」來看。
🔑 Takeaways
- 串流是「跑不完的批次」:輸入無界,所以要靠 window 把無限流切成可計算的有限桶。
- broker 選型分兩派:log-based (Kafka) 可重放多訂閱,傳統 AMQP 適合逐則 ack 的任務分派。
- 時間有兩種,event time 才誠實;代價是「到齊」不可知,得用 watermark + grace period 處理遲到事件。
- join 的本質是「流與狀態配對」:stream–stream 要時間視窗緩衝,stream–table 要把表看成 CDC 流重建的物化狀態。
2026-07-01
- Q: 既然 event time 比 processing time 準,為什麼不一律用 event time?
- A: 因為 event time 把一個棘手問題攤到檯面上:你永遠不知道某個視窗的事件是否到齊。用 processing time 時,「現在這一分鐘過了」是個明確訊號,視窗可以乾脆地關閉;用 event time 時,遲到的事件可能在幾秒、甚至幾小時後才到,你得靠 watermark 猜「應該到齊了」,還得決定遲到者要丟棄還是發修正。換句話說 processing time 簡單但會在系統抖動時說謊;event time 誠實但逼你正面處理不確定性。生產上常見折衷是 event time 開窗 + 合理 watermark + 一段 grace period 收遲到者,超過才丟。