資料管線設計 (Data Pipeline Design)
什麼是 Data Pipeline
把原始資料從產生處轉化、搬移到能被分析/消費處的整套系統 —— 從來源(source)到目的地(sink)的自動化流水線。
真正的挑戰:資料量大到無法即時處理?某步驟失敗會重複計算或遺失?上游格式改了下游怎麼辦?
核心決策:批次還是串流?
「這個資料需要多快被看到?」
- 「幾秒內」→ 串流(Stream)
- 「幾分鐘可接受」→ 微批次(Spark Streaming / Flink,窗口設短)
- 「幾小時/隔天」→ 批次(Batch)
| Batch(靜止資料 data at rest) | Stream(移動中資料 data in motion) | |
|---|---|---|
| 處理時機 | 累積一批一起處理(每小時/天) | 每筆產生後立刻處理 |
| 適合 | 報表、大規模轉換、ML 訓練、帳單 | 詐欺偵測、即時儀表板、個人化推薦、告警 |
| 優點 | 吞吐高、成本低 | 低延遲(秒~毫秒) |
| 缺點 | 延遲高 | 複雜度高(重試、不重複、亂序) |
技術棧
批次:MapReduce → Spark
- MapReduce(Google 2004):Map 階段拆小塊平行處理成 key-value;Reduce 階段聚合相同 key
- Apache Spark:解決 MapReduce 每步寫磁碟的痛點,中間結果留記憶體 → 快 10~100×。核心抽象 RDD / DataFrame
雖然 scheduler(Airflow/cron)最小間隔 1 分鐘,但一次 Spark batch 完整生命週期(cluster 啟動、JVM startup、query planning、讀寫 commit)約 5~8 分鐘。排程間隔必須 > job 執行時間 + buffer。延遲需求 < 10 分鐘必須轉串流。
串流:Kafka + Flink
- Kafka:分散式事件串流平台(高吞吐、持久化訊息 bus)。producer 發布到 topic,consumer 訂閱;保留一段時間(預設 7 天)→ 可重播(replay)
- Flink:現代串流主流框架
Flink Window(視窗):串流不能無限等,必須在時間範圍內聚合:
| 視窗 | 機制 | 例 |
|---|---|---|
| Tumbling(滾動) | 每 5 分一個、不重疊 | 過去 5 分訂單數 |
| Sliding(滑動) | 每 1 分更新、覆蓋過去 5 分 | 最近 5 分訂單數,每分更新 |
| Session(會話) | 按用戶活動分組,閒置 30 分結束 | 用戶 session |
事件「發生時間」≠「到達處理器時間」(手機離線時產生,網路恢復才送到)。用 event time 才正確,但要處理遲到事件。Flink 用 Watermark(聲明「這時間點前所有事件都到了」)—— watermark 推進就關閉視窗輸出。合理設 watermark 延遲(如允許遲到 10 秒)在準確性和延遲間平衡。
兩種架構哲學
| Lambda Architecture | Kappa Architecture | |
|---|---|---|
| 思想 | 批次層(正確性)+ 速度層(低延遲),serving 層合併 | 既然串流可重播歷史,只用一套串流 |
| 優點 | 兼顧正確性和即時性 | 架構簡單,只維護一套邏輯 |
| 缺點 | 維護兩套程式碼(批次+串流,同邏輯),任何改動要同步兩處 | 重播大量歷史不如 Spark;Kafka 長期保留成本高 |
現代公司越來越傾向 Kappa(維護兩套成本太高)。但題目強調「超大規模歷史分析(TB+)」時,Lambda 或純批次更合理。先問延遲需求,再決定架構。
ETL vs ELT、資料去哪
ETL(Extract-Transform-Load):傳統,轉換在進倉儲前完成 → 改邏輯要從 OLTP 重抽(耗時 + 衝擊線上)。
ELT(Extract-Load-Transform):原始資料先進強大分析 DB(BigQuery/Snowflake),再用 SQL 轉換 → 改邏輯直接在倉儲重跑,不碰源頭 → 現代雲端首選。
| 目的地 | 用途 | Schema | 代表 |
|---|---|---|---|
| Data Warehouse | 結構化、已清洗、分析查詢 | schema-on-write | BigQuery、Snowflake、Redshift |
| Data Lake | 原始、未處理(含非結構化) | schema-on-read | S3 + Parquet、HDFS |
| Data Lakehouse | 結合兩者(物件儲存 + ACID/schema 演化) | — | Delta Lake、Apache Iceberg |
三個常見管線模式
| 模式 | 解決 | 機制 |
|---|---|---|
| CDC(變更資料捕捉) | 不影響線上 DB 下同步到別系統 | 監聽 WAL,把 INSERT/UPDATE/DELETE 轉 Kafka 事件(Debezium)→ 下游訂閱 |
| Fan-out(扇出) | 一個事件觸發多個下游 | App server 只發一個事件到 Kafka,各下游獨立訂閱(pub/sub)→ 完全解耦 |
| Data Enrichment(豐富化) | 補充多來源資料 | 流過管線時從 side input 動態補(用戶 profile 存 Redis 快取避免每筆查 DB) |
需在不影響線上 DB 效能下把資料同步到另一系統時,CDC + Kafka 是標準答案。也用於搜尋索引更新 → 詳見 08-Search-and-AI/01-Search-System。
容錯機制
三種語意保證
| 保證 | 含義 | 取捨 |
|---|---|---|
| At-most-once | 最多一次,可能遺失 | 最簡單,但遺失通常不可接受 |
| At-least-once | 至少一次,可能重複 | 大多數系統預設,失敗重試 |
| Exactly-once | 精確一次 | 最強但代價最高,需框架 + 下游協作 |
Exactly-once 難完美實現且有效能代價。實務上選 at-least-once,下游做冪等處理(INSERT ... ON CONFLICT DO NOTHING 或 upsert),即使同筆進來兩次結果也一樣。比追求 exactly-once 更簡單可靠。
Checkpointing:串流處理器定期把狀態(offset、聚合中間結果)寫持久儲存(S3)→ 崩潰後從最近 checkpoint 恢復。頻率取捨:太頻繁 I/O 大、太少崩潰後重處理多。
常見 Deep Dive
- 多開 consumer:Kafka partition 數決定最大並發(100 partition → 100 consumer)
- 批次補跑:起獨立 Spark job 專跑那段時間,和串流並行消化
- 優先級:先處理最新資料(保當前及時性),再回頭補舊的
- Schema Registry(Confluent):不合 schema 的事件自動被拒
- 資料品質監控:null rate 超閾值告警、數值分佈異常告警(dbt、Great Expectations)
- DLQ(死信佇列):解析失敗的事件送 DLQ 隔離,別讓管線崩潰
- 向後相容(新增/可選欄位):舊消費者忽略新欄位即可
- 向前相容(移除欄位):新消費者讀舊資料需有預設值
- 用 Avro / Protobuf + Schema Registry 強制相容性規則
常見系統範例
| 系統 | 批次 vs 串流 |
|---|---|
| 分析儀表板 | 「過去 24h GMV」批次 + 「即時訂單數」串流 → Lambda 或混合 |
| 推薦系統 | feature engineering 批次(每天)+ 「剛點了什麼」串流 |
| 監控告警 | 全串流(log 收集 + 即時視窗聚合偵測 p99 飆升) |
| 搜尋索引更新 | DB 變更 CDC → Kafka → ES 訂閱即時更新 |
先問延遲需求 → 識別來源/目的地 → 說明轉換複雜度 → 主動說容錯策略。表現出你從需求推導技術選擇,而不是把技術砸進去。
Related Notes
- 10-Design-Patterns/02-Scaling-Writes — Write Queue、階層式聚合
- 10-Design-Patterns/03-Long-Running-Tasks — Message Queue、DLQ、idempotency
- 08-Search-and-AI/01-Search-System — CDC + Kafka 同步搜尋索引
- 05-Database-Advanced/03-Replication — WAL、CDC 的基礎
- 02-Distributed-Systems/02-CAP-Theorem — exactly-once / 一致性取捨
- 09-Messaging-Coord/Practice-Messaging-Coord