題目與適用場景
這是給中高階資料工程師的 Schema 演進題。事件既供即時指標使用,也會落入湖倉;消費者版本不同,部分團隊無法同日升級。假設系統至少一次投遞、事件可重播,契約需要約束欄位型別、語義、品質、時效與安全邊界。
面試官考察點
- 強回答會把「欄位能解析」與「商業含義沒有改變」分開。
- 能否建立生產者與消費者的相容性矩陣,而不是只說「加欄位通常安全」。
- 是否用血緣與使用紀錄找出受影響欄位、查詢與儀表板。
- 能否把契約檢查放進 CI、發布門禁與執行期,並設計可回滾的雙讀或雙寫。
回答前需要釐清的問題
先確認事件格式與註冊位置、目前 amount 的單位與範圍、消費者是否允許未知欄位、是否存在舊訊息重播,以及 currency 缺失時的商業含義。若金額改變的是單位或捨入規則,即使二進位型別可解析也屬於語義破壞;若新欄位只是可選中繼資料,遷移路徑會不同。也要確認能否追蹤消費者版本、是否允許短期雙版本主題,以及即時延遲與回填窗口。
30 秒回答框架
我會先把契約定義為 Schema、欄位語義、品質規則、時效、擁有者與安全約束,再盤點血緣和消費者能力。amount 不能直接改含義;我會發布新版本或新欄位,保持舊投影可讀,先做相容性 CI 與影子驗證,再按消費者分批切換。執行期拒絕或隔離違規事件,記錄版本與品質指標;完成遷移後保留明確棄用期,能從舊事件重建舊投影,並用對帳與重播證明結果一致。
分步驟深入解答
- 寫出契約邊界。 除欄位名稱與型別,也記錄單位、精度、可否為空、列舉、主鍵、事件時間、時效目標、PII 標籤、擁有者和破壞性變更審批。OpenMetadata 的契約模型也把 Schema、語義、SLA、安全、品質測試與責任人放在同一治理物件。
- 建立變更分類。 新增可選欄位通常對舊解析器向後相容;刪除、改型別、收窄範圍、改變單位或把可選改必填都先視為破壞性。
amount從整數分改為定點金額會改變語義,應新增標準化欄位或版本,而非靜默覆蓋舊欄位。 - 做影響分析。 從 OpenLineage 的 Dataset、Job、Run 與 Schema Facet 找到讀寫作業、下游資料表、欄位血緣與最近執行。對 40 個消費者記錄解析器版本、欄位使用、是否重播與切換負責人,形成「變更 × 消費者」矩陣。
- 設計遷移。 一段時間內同時發布
amountminor與amountdecimal,或發布 v2 事件;舊消費者繼續讀舊投影,新消費者先影子讀新欄位。currency 作為可選欄位發布,但只有能證明預設值不改變商業含義時才填入。 - 設定門禁。 CI 比較候選契約與已註冊版本,檢查型別、必填性、列舉和語義變更;通過後再做樣本重播、品質斷言與消費者契約測試。生產入口驗證事件版本,違規訊息進入隔離佇列並帶上生產者、契約版本與原因。
- 切換與回滾。 按消費者分批切換,觀察解析錯誤、缺失率、金額對帳、延遲與重播結果。若新投影錯誤,停止新版本生產並回退讀取路徑;舊事件仍可重建舊投影。不要刪除舊欄位,直到最後一個消費者與重播窗口都越過棄用線。
- 記錄可追責性。 OpenLineage 要求執行事件描述 Job、Run、輸入和輸出,Schema Facet 可記錄資料集欄位;把契約版本、Git 提交與驗證結果寫進血緣事件,才能解釋哪次發布改變了哪個下游結果。
高品質示範回答
我不會把這次修改當成普通欄位新增。先把 amount 的單位、精度與捨入規則寫入契約,並查詢血緣確認 40 個消費者到底把它當成整數分、顯示值還是聚合鍵。OpenMetadata 的資料契約概念涵蓋 Schema、語義、SLA、安全、品質測試與負責人;這提醒我檢查「可解析」之外的商業保證。
接著註冊 v2 或相容的雙欄位版本:保留 amountminor,新增明確精度的 amountdecimal 與可選 currency。CI 對新版本做相容性檢查,消費者契約測試涵蓋未知欄位、缺少 currency、舊訊息重播與精度邊界。發布時先影子計算新投影,再按消費者切換;執行期門禁拒絕沒有合法契約版本的訊息,把失敗事件隔離並告警。
切換期間我看金額對帳、欄位缺失率、解析錯誤、延遲和重播差異。任何差異都先停止新版本寫入,恢復舊投影讀取,利用保留的事件重建結果。只有所有消費者完成切換、重播窗口結束、棄用指標歸零後,才刪除舊欄位。OpenLineage 的 Job、Run、Dataset 與 Schema Facet 記錄契約版本和執行結果,使影響分析與稽核可重現。
常見錯誤
- 只驗證 JSON 能解析 → 把型別相容誤當語義相容 → 將單位、精度、空值與範圍寫進契約並單獨評審。
- 看到「新增欄位」就直接發布 → 嚴格解析器或必填檢查會失敗 → 先盤點消費者能力,必要時發布版本或雙欄位。
- 只在生產後觀察錯誤日誌 → 已寫入的錯誤資料無法快速恢復 → 在 CI、樣本重播和執行期分別設定門禁與隔離。
- 修改後立刻刪除舊欄位 → 重播和延遲消費者失去讀取路徑 → 設定棄用期,直到消費者與重播窗口都完成。
- 把血緣當靜態目錄 → 無法回答哪次執行受影響 → 關聯 Job、Run、Dataset、Schema Facet、版本與驗證結果。
追問及應對
如果一個遺留消費者無法升級怎麼辦?
保留相容的舊投影或轉換層,讓新事件同時產出舊視圖;給它設定明確的擁有者、截止日期和錯誤預算。不能為了一個消費者永久凍結契約,也不能讓轉換層悄悄改變金額語義。
如果 currency 缺失且無法安全推斷怎麼辦?
把缺失視為契約違規或未知狀態,不填入看似合理的預設值。隔離事件並通知生產者;若業務允許,另行發布「未指定幣別」的明確列舉,並在下游指標中排除或分組顯示。
如何證明回滾沒有重複計算金額?
使用事件 ID、契約版本與投影版本做冪等鍵,分別重播舊、新投影,比較依訂單與幣別聚合的結果。記錄差異樣本、捨入規則與輸入快照;只有對帳通過後才恢復新版本寫入。