設計資料契約 是做什麼的?
使用時機
- 上游(服務、事件、API、檔案)饋送下游管線,且變更可能無聲破壞管線時。
- 定義生產團隊/系統與資料倉儲之間的介面。
- 在擷取邊界加入綱要/品質強制執行。
- 不適用於 同一 dbt 專案內的內部模型到模型變更(請使用測試 +
handling-schema-evolution)。
契約應指定內容
- 綱要:欄位、型別、可空性及允許值。
- 語義:每個欄位的意義及其單位/粒度。
- 保證:新鮮度/SLA、資料量預期、鍵的唯一性。
- 擁有權:誰生產資料以及聯絡人。
- 版本管理 + 變更政策:如何溝通破壞性變更。
工作流程
- [ ] 將契約寫成版本化、可簽入的綱要(非 tribal knowledge)
- [ ] 在擷取邊界強制執行(資料到達時驗證)
- [ ] 分類變更:新增(安全) vs. 破壞性(需要新版本)
- [ ] 發生違規時,拒絕/隔離並通知生產者
- [ ] 提前版本化並溝通破壞性變更
- 明確且版本化。 將契約以程式碼形式儲存(JSON Schema、Avro/Protobuf schema 或 YAML 規格),置於管線旁,像 API 一樣接受審查。
- 在邊界強制執行。 資料到達時立即依據契約驗證;違規則拒絕或隔離,而非載入。
- 分類變更。 新增/選用欄位 = 向後相容。移除欄位、重新命名、收緊型別/可空性 = 破壞性 → 新版本。
- 向生產者大聲失敗,而非在下游無聲破壞。
模式
契約以 JSON Schema 形式(在擷取時強制執行):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["order_id", "amount", "ordered_at"],
"properties": {
"order_id": { "type": "string" },
"amount": { "type": "number", "minimum": 0 },
"ordered_at": { "type": "string", "format": "date-time" },
"coupon": { "type": ["string", "null"] }
},
"additionalProperties": false
}
強制執行點 — 在資料擷取時驗證每一筆記錄;將失敗記錄路由至附有原因的 quarantine 位置,並通知生產團隊。如此可將無聲的下游錯誤轉變為即時、有歸屬的來源訊號。
Schema Registry(Kafka/Avro) — 在發佈時強制執行相容性(BACKWARD),使生產者無法發佈不相容的綱要。
常見陷阱
- 契約僅作為文件 — 若未在程式碼中強制執行,它會偏移並無聲破壞。
- 在資料倉庫深處執行 — 應在邊界捕捉違規,避免不良資料擴散。
- 無版本管理 — 每次變更都變成緊急事件;應版本化並優雅地棄用。
- 未限制
additionalProperties當你需要嚴格性時 — 意外欄位會溜進來;視情況設為 false。 - 無擁有者 — 被拒絕的批次若無人可聯絡,會使管線停滯。
- 破壞性變更無預告期 — 應透過版本化綱要與棄用窗口協調生產者/消費者。