具代表性的面試主題

資料工程面試:Apache Iceberg 如何安全演進 Schema 與分區?

資料困難
OfferCC 編輯團隊發佈 更新

題幹

請解釋 Apache Iceberg 如何在不重寫舊資料檔案的情況下演進 Schema 與分區。欄位 ID、Schema ID、Partition Spec ID 各自解決什麼問題?你會如何驗證相容性、效能和回滾能力?

題幹與適用場景

一張訂單湖表已被批次、串流和臨時分析共同讀取。業務要新增巢狀欄位、重新命名欄位,並把按月分區逐步改成按日分區;舊任務不能同時升級,也不想完整重寫歷史檔案。你要說明 Iceberg 如何儲存演進,以及新舊布局共存時如何維持正確性。

預設表由 Iceberg Catalog 管理,讀寫引擎支援目標版本;題目重點是表格式的 Schema 與分區演進,不是特定 Spark SQL 語法。

面試官考察什麼

  • 能否區分欄位 ID、Schema ID、Partition Spec ID 和快照。
  • 能否解釋為何新增、刪除、重新命名和型別擴展不必重寫舊檔案,以及仍有哪些限制。
  • 能否說明新舊分區如何共存、查詢如何規劃多個分區規範,何時需要重寫資料。
  • 能否提出遷移前後的相容性、效能、並行提交和回滾驗證。

回答前要釐清的問題

  1. 讀者使用 Iceberg 原生表格式,還是只把目錄當作 Hive 表?後者不會自動取得同樣的欄位 ID 語意。
  2. 要演進的是頂層欄位、巢狀欄位,還是分區轉換?巢狀結構和分區欄位有額外限制。
  3. 舊讀者是否按位置讀取欄位或快取舊 Schema?必須確認引擎遵守 Iceberg 的欄位 ID 對應。
  4. 目標是減少掃描、修復熱點,還是只改變邏輯 Schema?分區調整的收益要用查詢指標驗證。

30 秒回答框架

「Iceberg 把表狀態放在版本化元資料中,用不重複的欄位 ID 對應欄位,而不是依賴位置或重用名稱。Schema 變更產生新的 Schema ID,分區變更產生新的 Partition Spec ID;舊資料檔案保留原布局,新寫入使用新規範,查詢會針對多個規範分別規劃並利用隱藏分區裁剪。我會先做相容性檢查,再以元資料提交原子發布變更,最後用新舊讀者、重新命名正確性、掃描檔案數、失敗重試和快照回滾驗證。」

分步深入分析

1. 用欄位 ID 維持欄位身分

Iceberg 為每個欄位分配表內不重複的 ID。重新命名只改名稱,讀取仍按 ID 找到原欄位;刪除後再使用同名欄位會得到新 ID,避免舊檔案的值被錯誤復活。按位置或重用名稱都可能造成錯配。

text
舊 Schema: id=17, name="customer_id"
新 Schema: id=17, name="account_id"
新增欄位: id=42, name="region"

2. 區分 Schema ID 與欄位 ID

欄位 ID回答「這個欄位是誰」;Schema ID回答「這一版表結構是什麼」。一次演進會產生新的 Schema 物件並設為目前 Schema ID,快照記錄寫入時使用的 Schema ID。讀者不能只快取欄位名稱陣列。

3. 判斷哪些 Schema 變更安全

新增、刪除、重新命名、重排和部分型別擴大是 Iceberg 支援的演進,但不表示所有型別變更都安全。要檢查格式版本、分區轉換和取值範圍;參與 bucket 轉換的欄位若改變轉換結果,會破壞分區語意。Map key 的結構變化也有限制。

text
安全候選:增加可選欄位、重新命名非分區欄位、int -> long(轉換結果不變)
需要阻擋:縮窄型別、改變 bucket 輸入語意、刪除仍被關鍵讀者依賴的欄位

4. 讓新舊分區規範共存

分區演進會建立新的 Partition Spec ID;舊檔案仍使用舊規範,新檔案使用預設的新規範。讀取時要按每個規範解釋檔案,再合併結果。隱藏分區讓查詢按資料值表達過濾條件,不必把某個日期目錄寫死在 SQL。

5. 評估「不需重寫」與查詢效能

元資料變更不重寫資料檔案,降低遷移成本,但舊檔案仍按舊布局保存。多規範共存可能讓查詢產生多組 split,裁剪效果也不同。比較掃描檔案數、規劃時間、讀取位元組、任務傾斜和小檔案數;舊布局若持續成為熱點,再用受控重寫改善。

6. 用原子提交、快照和回滾保護發布

表狀態由元資料檔案和快照組成,更新透過原子替換目前元資料指標提交。發布前讀取目前版本,基於該版本建立新元資料並提交;衝突時重新讀取再重試。把變更與快照 ID 綁定,讀寫錯誤時可以切回已驗證快照。

高品質示範回答

我會把需求拆成欄位身分、結構版本和物理布局三層。欄位 ID 保證重新命名和重排不會把舊檔案的值映射錯;Schema ID 記錄這一版結構;Partition Spec ID 記錄這一版分區轉換。新增 region、重新命名 customer_id 等元資料操作不需要重寫舊檔案,但要先確認所有引擎按欄位 ID 讀取。

分區從月改日時,我會建立新規範讓新寫入使用它,保留舊檔案規範。查詢規劃器要對每個規範使用對應分區表達式,再合併 split。發布前做新舊讀者讀寫矩陣,抽樣比較重新命名前後的值,測掃描檔案數和讀取位元組,並在隔離分支提交變更。若衝突或指標惡化,按快照回滾;舊布局若長期拖慢熱點查詢,再安排有預算的重寫。

常見錯誤與改進

  • 錯誤表現 → 認為改欄名等同於改檔案欄位順序 → 失敗原因 → 位置綁定會錯配值 → 修正方法 → 說明欄位 ID 的穩定身分並驗證引擎使用它。
  • 錯誤表現 → 演進分區後只掃描新目錄 → 失敗原因 → 舊檔案仍屬於表,結果會漏資料 → 修正方法 → 保留並解釋每個 Partition Spec,使用規範感知的規劃。
  • 錯誤表現 → 「不重寫檔案」就代表沒有效能成本 → 失敗原因 → 多規範 split 和舊布局仍可能增加掃描 → 修正方法 → 測規劃時間、檔案數、位元組和傾斜,必要時分批重寫。
  • 錯誤表現 → 直接覆蓋目前元資料 → 失敗原因 → 並行提交或失敗重試可能遺失更新 → 修正方法 → 基於讀取版本原子提交,衝突時重新讀取並保存回滾點。

追問及應對

為什麼不能刪除欄位後再使用同名欄位?

可以重新新增,但必須取得新的欄位 ID。若重用舊 ID,舊檔案原欄位的值可能被誤讀成新欄位,破壞刪除語意。驗證要檢查舊檔案、新檔案和同名重建後的 ID。

把 int 提升成 long 一定安全嗎?

不一定。要檢查格式版本、取值範圍、下游型別及欄位是否參與分區轉換。若 bucket 等轉換的輸入結果改變,舊新檔案的分區語意可能不一致;應阻擋變更或先設計新規範。

舊檔案按月、新檔案按日,查詢會不會漏讀?

正確實作不會因規範不同而漏讀。查詢應針對每個 Partition Spec 解釋檔案分區值並分別裁剪,再合併結果。測試要包含跨越演進時間點的範圍查詢,並與全表掃描的資料列集合比對。

什麼時候仍需要重寫資料檔案?

當舊布局造成持續掃描、傾斜、小檔案或儲存成本時,才用受控重寫改善物理狀態;Schema 或分區元資料演進本身不要求重寫。重寫要有快照、並行提交和預算,避免變成不可回滾的大遷移。

公開來源

同類題目

資源

產品比較

每份比較均依官方資料整理,並標示複核日期。

查看完整比較