Lambda architecture 是把同一份統計分成兩條路徑計算的做法:批次層(batch layer)定期從完整的原始事件重算出正確的數字,即時層(speed layer)在事件發生的當下累加,補上批次層還沒算到的最近那一段。查詢時由合併層(原始定義稱為 serving layer)合併兩者:較早的時段讀批次層,最近的時段讀即時層。批次層的結果是權威,即時層的數字遺失或偏差時,等批次層算到那一段就被取代。它和 Materialized View 同樣是預先算好的結果,差別在於 materialized view 只有一份、刷新前讀到的是舊值;兩條路徑的做法用即時層填補刷新之間的空檔。其他中文資料常寫作 Lambda 架構。

概念位置

路徑輸入結果的性質常見載體
批次層保存期限內的全部原始事件可重算、規則改了可以全部重新算資料庫裡的彙總表、資料倉儲的排程查詢
即時層事件發生當下的那一筆只能累加、不能修正,遺失就是少算了Redis 的計數與 HyperLogLog、串流處理的視窗聚合

兩條路徑寫兩份計算邏輯,是這個做法主要的維護成本。Kappa architecture 只留一條串流路徑,要重算時從事件記錄的開頭重播;適合事件本身長期保存在可重播的事件記錄裡(例如 Kafka)的系統。把事件長期保存、以重播重建狀態的設計見 Event Sourcing。

可觀察訊號與例子

  • 同一個時段兩份數字不一樣:即時層只累加原始的點擊,批次層依規則排除機器人之後才計數,同一個小時在即時層看到的數字比較大。介面上要標示即時層的數字是「未分類、尚未定案」,或兩者的口徑一致。
  • 最近幾分鐘的數字突然變小:即時層的資料庫重啟或切換節點,遺失了最近的累加。等批次層算到那一段就補回來;若批次層也偏低,問題出在原始事件的寫入,不在即時層。
  • 切換點的重複或缺漏:合併時以「批次層已經完成到哪一個時段」為界,界線以前讀批次層、以後讀即時層。界線用「現在減一小時」這類固定值時,批次層落後的那一段會兩邊都沒有。

實例:短網址的點擊在轉址時以 Redis 的 HINCRBY 依連結與小時累加,後台看目前與前一個小時的數字時讀它;更早的時段讀資料庫裡依原始事件重算的小時表。詳見 1.18 高頻計數的寫入與彙總:熱點列的鎖、只新增的事件、可以重跑的彙總與重送的事件〈Redis 在計數、去重與互斥裡的位置〉。

設計責任

先確認需求方真的需要比批次層更新得更快的數字:批次層每分鐘重算一次就夠用時,即時層只增加一份要維護的邏輯。採用時寫下三件事:哪一層是權威、兩層的界線由什麼決定、兩層的計數口徑有沒有差別以及介面怎麼標示。即時層的資料不需要備份,它的遺失由批次層吸收。