具代表性的面試主題

資料工程面試:如何為事件 Schema 設計相容性發布閘門?

資料困難
Offer.cc 編輯團隊發佈 更新

題幹

訂單事件有多個生產者與消費者,需要增加、重命名和淘汰欄位。請設計 Schema Registry 相容性閘門、發布順序、觀測與回滾。

題幹與適用場景

訂單事件由多個團隊生產與消費。新版本要增加可選欄位、重命名一個欄位並淘汰舊欄位;消費者無法同時升級,歷史訊息仍會重放。請設計從變更提案、相容性檢查、灰度發布到回滾的閘門,並說明 Avro writer/reader schema、Schema Registry 相容模式和資料品質驗證如何配合。

這題考察資料契約、Schema 演進、串流發布與營運治理。Schema Registry 能集中儲存版本、校驗相容性並讓生產者與消費者共享契約,但具體規則會隨 Avro、JSON Schema 或 Protobuf 格式而變。

面試官在考察什麼

  • 是否區分 backward、forward、full 與 transitive,而不是把「相容」當成單一布林值。
  • 能否從 writer schema 與 reader schema 的實際部署窗口推導發布順序。
  • 能否把註冊前檢查、執行期 schema ID、消費者 lag 和資料品質接成閘門。
  • 能否處理重命名、預設值、刪除、列舉和不可逆變更的遷移與回滾。

先釐清哪些問題

  1. 使用 Avro、JSON Schema 還是 Protobuf?格式不同,解析與相容細節不同。
  2. 消費者是即時、批次還是會重放歷史?最老 writer 版本保留多久?
  3. 生產者和消費者誰先發布,是否存在跨區域或跨團隊的長尾版本?
  4. Topic 按團隊、事件類型還是環境劃分 subject?相容級別是全域還是按 subject?
  5. 回滾是恢復舊生產者、停止發布,還是需要雙寫新舊欄位?

30 秒回答框架

先建立版本與消費者窗口,再選相容方向:新消費者讀舊訊息需要 backward,舊消費者讀新訊息需要 forward,兩者都要求時才考慮 full,並依最老版本選擇 transitive 檢查。所有 Schema 先在註冊閘門校驗,再按「讀者先、寫者後」安全順序灰度;新增欄位提供預設值,重命名採 alias 或雙欄位遷移,刪除要等消費者窗口結束。執行期監控 schema 註冊拒絕、反序列化錯誤、lag、死信與關鍵欄位品質,異常時停止推廣並保留舊版本。

分步作答

1. 明確 writer 與 reader 的部署矩陣

訊息攜帶或關聯 writer schema;消費者用 reader schema 解析。畫出舊生產者/新生產者與舊消費者/新消費者四種組合,標記哪些組合必須支援。即時升級通常先讓新消費者能讀舊資料,再讓舊消費者能讀新資料,最後才切換生產者。

2. 把相容模式綁定到風險

Backward 檢查新 reader 能否讀舊 writer;forward 檢查舊 reader 能否讀新 writer;full 同時檢查兩者。若需要跨越多個歷史版本,選 transitive 語意或顯式測試版本集合。不要把某個註冊中心預設值當成所有格式的通用規則。

3. 設計變更規則

增加欄位時給出安全預設值並驗證業務含義;重命名優先使用格式支援的 alias,或先雙寫舊、新欄位,再遷移 reader;刪除欄位要等最老消費者與重放窗口結束。列舉新增值要確認舊消費者的未知值行為,型別收窄、含義改變與單位改變應視為破壞性變更。

text
propose -> lint -> compatibility-check -> consumer-matrix-test
        -> register -> canary-producer -> observe -> expand

4. 建立註冊與 CI/CD 閘門

PR 階段執行格式 lint、規範化 diff、subject 級相容檢查與代表性歷史樣本反序列化。註冊中心保留 schema ID 與版本;發布工具拒絕繞過檢查的生產註冊。相容級別可按 subject 管理,不能只改全域設定而忘記局部覆蓋與權限稽核。

5. 按讀者先、寫者後的順序灰度

先發布能讀舊版本的新消費者,觀察反序列化錯誤與 lag;再雙寫或發布新生產者;最後停止舊消費者和舊欄位。跨團隊長尾消費者要有清單、負責人與截止時間,不能用「大家升級後再發」作為控制面。

6. 執行期品質與回滾

監控 schema ID 未知、反序列化失敗、死信量、欄位缺失率、單位異常、消費者 lag、重放成功率與註冊拒絕數。回滾優先停止新生產者並恢復仍相容的舊 writer;若語意已改變,保留新 topic 或版本化 subject,避免把舊資料強行解釋成新含義。

高品質示範答案

我會先畫出 writer/reader 部署矩陣,確認要支援的舊生產者、舊消費者和重放版本,再按格式選擇相容規則。新 reader 讀舊訊息是 backward,舊 reader 讀新訊息是 forward,兩者都要支援才考慮 full;跨多個歷史版本則做 transitive 檢查。所有變更先經過 lint、subject 級註冊檢查與歷史樣本反序列化。

發布順序是讀者先、寫者後:先灰度新消費者,再雙寫或切換新生產者,最後等待消費者窗口結束後刪除舊欄位。新增欄位給預設值,重命名用 alias 或雙欄位過渡,刪除和列舉變化都要驗證舊客戶端行為。線上觀察註冊拒絕、反序列化錯誤、lag、死信與欄位品質;異常時停止擴散、保留舊 schema,必要時回到舊生產者或新舊 topic 分流。相容模式必須按具體格式驗證,不能把一個產品的預設規則當成 Avro、JSON Schema、Protobuf 的共同語意。

常見失分點

  • 只說「啟用 backward」,卻不說明誰是 reader、誰是 writer。
  • 直接重命名或刪除欄位,忽略 alias、雙寫和歷史重放。
  • 只在註冊時檢查 Schema,不測試真實歷史訊息和舊消費者。
  • 先發布新生產者,導致舊消費者收到無法解析或語意錯誤的資料。
  • 把全域相容設定當成 subject 級策略,忽略權限和設定漂移。
  • 只監控 Kafka lag,不監控欄位缺失、單位變化、死信與反序列化錯誤。

追問與參考回答

新增欄位為什麼常要求預設值?

舊訊息沒有該欄位,新 reader 需要確定值才能建立記錄;預設值必須符合業務語意,不能用空值掩蓋必填資料缺失。

重命名欄位應直接改名嗎?

通常不應直接改。可先用 alias 或同時寫舊、新欄位,遷移所有 reader 後再刪除舊欄位,並保留足夠重放窗口。

full 與 full transitive 有什麼風險差異?

full 通常檢查目前相鄰版本的雙向相容;transitive 會擴大到歷史版本集合,閘門更嚴格但升級成本更高,應依保留與重放範圍選擇。

為什麼 schema 註冊成功仍可能遺失資料?

相容性只覆蓋結構解析,不保證業務單位、列舉語意、欄位品質、權限或下游 SQL 正確;要結合樣本回放、品質規則和執行期觀測。

如何為長尾消費者設定退出條件?

登記 owner、版本、最後消費時間與重放需求,設定明確截止日期與告警;到期前提供遷移工具,到期後先隔離或拒絕舊版本,而不是永久放寬相容規則。

什麼時候應該新建 subject 或 topic?

當語意、單位、生命週期或權限邊界已改變,無法透過相容演進表達時。新版本隔離可降低誤解析風險,但要承擔雙寫、回放和治理成本。

公開來源

同類題目