題幹與適用場景
一個 B2B 產品要提供全量或增量資料匯出。單次匯出可能超過請求逾時和單檔大小,客戶端也可能在下載中斷後重試。面試重點是如何定義匯出邊界、非同步狀態、檢查點、檔案可見性、權限與資源配額。
面試官考察什麼
面試官會看你能否把長任務拆成可觀察、可恢復的協定。Google Data Portability API 將匯出作為獨立能力並要求敏感範圍審核;Zendesk 的增量匯出用 cursor 或時間邊界保存下一次起點,並明確避開最近一分鐘的競態;Oracle FHIR Bulk Export 透過 Content-Location 回傳任務位址供客戶端輪詢。高品質回答還要說明快照一致性、刪除語義與租戶隔離。
回答前要澄清的問題
先確認匯出資源、全量或增量、最大筆數和保留時間;匯出是否必須跨表一致、能否接受某個時間點快照;結果是 JSONL、CSV 還是壓縮分片;客戶端是否需要取消和斷點下載;誰能發起、誰能下載;每租戶並發、頻寬和儲存預算是多少。不要把「匯出完成」與「檔案已下載」混為一個狀態。
30 秒回答框架
可以這樣開場:「我把協定分成建立任務、查詢狀態、下載清單和取消四類操作。建立時固定授權範圍與快照邊界,回傳任務 ID;背景 worker 按分片讀取並持久化檢查點,產出不可變檔案清單。客戶端輪詢任務位址,完成後只取得短期下載憑證。檢查點和冪等鍵讓 worker 重試不會重複計數,過期任務會刪除檔案並釋放配額;增量匯出使用 cursor 或封存的高水位,避免時間邊界造成漏資料。」
分步驟深入分析
第一步:建立任務並凍結匯出邊界
POST /exports 驗證租戶權限、資源範圍、篩選條件和配額,產生不可猜的 exportId。任務記錄授權快照、格式、壓縮方式、建立時間、過期時間和 snapshotWatermark。資料庫支援一致性快照時,在同一交易中讀取水位;否則明確這是各資源分別截取的近似快照,不能宣稱跨表嚴格一致。
第二步:非同步狀態與冪等
建立請求接受 Idempotency-Key,相同租戶和 key 回傳同一任務。GET /exports/{id} 回傳 QUEUED、RUNNING、SUCCEEDED、FAILED、CANCELLED 或 EXPIRED,並給出已處理分片、預計範圍和下一步動作。狀態機只允許單向推進,取消與完成並發時用條件更新決定勝者,重試不能重新扣配額。
第三步:分片讀取與持久化檢查點
worker 按穩定主鍵或資料庫提供的快照游標讀取固定批次,將結果寫入暫存物件。每個分片保存 (exportId, partition, cursor, rowCount, checksum, objectKey);提交檢查點和分片中繼資料要冪等。worker 崩潰後從最近已提交 cursor 重跑,重複分片使用版本號或物件條件寫入覆蓋,最終清單只引用一次。
第四步:全量與增量的邊界語義
全量匯出在 snapshotWatermark 之前讀取,之後新增或更新的資料留給下一次增量。增量任務從上次保存的 cursor 或高水位開始,而不是簡單使用目前時間減一秒。Zendesk 文件說明 cursor 可作為下一頁和下一次匯出的起點,並用安全延遲避開最近寫入的競態;設計中應把延遲、重複和補償窗口寫進協定。
第五步:完成、清單與下載
所有分片完成並校驗後,任務原子地從 RUNNING 變為 SUCCEEDED,產生不可變 manifest(檔案、大小、校驗和、資料範圍)。下載介面只回傳短期、綁定租戶和物件的憑證;憑證不授予任意物件存取權。下載失敗可重新取得同一 manifest,不重新執行匯出。檔案在過期前保持唯讀,避免下載途中內容變化。
第六步:資源保護、取消與清理
建立和 worker 排程都檢查租戶並發、掃描列數、CPU、物件儲存和出口頻寬配額。大型任務進入佇列並設全域並發上限,線上請求使用獨立資源池。取消後停止新分片、標記任務並非同步刪除暫存檔案;EXPIRED 任務由可重試清理器回收,記錄孤兒位元組、失敗原因和清理延遲。管理員可在稽核日誌看到發起人、範圍與下載事件。
高品質示範回答
「我會用 POST /exports 建立任務,驗證租戶權限與配額並保存授權範圍、格式、過期時間和快照水位,支援冪等 key。回應只回傳 exportId,客戶端透過 GET /exports/{id} 輪詢。worker 從快照游標按主鍵分批讀取,每個分片持久化 cursor、筆數和 checksum;重試從最近檢查點繼續,重複寫入由 (exportId, partition, cursor) 條件保證冪等。全量使用固定水位,增量保存 cursor 或高水位並帶安全延遲,避免漏資料。所有分片完成後產生不可變 manifest,任務原子進入 SUCCEEDED,下載介面發短期、綁定租戶的憑證。取消和過期會停止新工作、刪除暫存物件並釋放配額;限速、資源池和稽核保護線上流量。」
常見錯誤與改進
- 在 HTTP 請求中同步掃描全表: 改為任務佇列和可輪詢狀態,避免逾時佔滿連線。
- 用目前時間做增量起點: 保存 cursor 或封存高水位,並定義安全延遲與重複處理。
- 每次重試都產生新檔案: 以分片檢查點和 manifest 冪等,重試只補缺失部分。
- 下載連結長期有效: 憑證綁定租戶、物件和過期時間,下載失敗只重新簽發同一檔案。
追問及應對
匯出期間有資料被刪除怎麼辦?
先定義產品語義。快照匯出只保證水位前存在的資料;增量流應攜帶刪除墓碑或變更類型。清理墓碑前要滿足消費者保留窗口,否則下游無法知道刪除。
worker 在寫完檔案但提交檢查點前崩潰怎麼辦?
重啟時以資料庫檢查點為準重跑該批次。物件寫入使用確定的分片版本或條件覆蓋,manifest 只採納已提交且校驗通過的版本,因此不會把半成品暴露給下載者。
如何避免一個租戶拖垮線上資料庫?
為匯出使用唯讀副本、快照或專用查詢資源池,限制掃描並發和每秒列數;佇列按租戶公平調度,監控副本延遲、鎖等待和出口頻寬,超過閾值自動降速或暫停。
客戶端需要從中斷位置繼續下載怎麼辦?
匯出結果保持不可變並支援 HTTP Range 或分片下載。客戶端保存 manifest、檔案校驗和已下載範圍;重新取得憑證不會改變檔案版本,也不會重新執行匯出。