Snorkel AI 的 CI/CD 流水線為每一個開放的拉取請求(PR)都配置了獨立的 Lakebase Postgres 分支。這個分支是生產數據的完整讀寫副本,可在不到一分鐘內準備就緒,而以往完整恢復一份副本往往需要 30 分鐘甚至更久,這也正是他們此前始終無法為每個 PR 啓用副本的根本原因。Lakebase 分支採用寫時複製(copy-on-write)機制,因此在約 2.5 TB 的生產數據集上,即便同時存在 100 個 PR 數據庫,新增存儲也僅限於每個分支實際修改的數據。分支過期(TTL)機制會在對應 PR 結束後自動清理分支,使存儲規模基本維持在生產數據本身加上活躍 PR 變更的水平。私有網絡連接與 Okta SSO 支持,則共同提供了受治理且安全的環境。
問題的核心在於:面向生產數據的測試不該耗時 30 分鐘以上。Snorkel AI 為 AI 團隊構建數據開發工具,其用户包括專家級數據標註人員和前沿模型提供商。在該用例中,Snorkel 通過基於 Kubernetes 構建的 CI 流水線發佈代碼。每個開放的拉取請求以及臨時提交都會獲得各自的臨時 Kubernetes 命名空間(即“PR 命名空間”)。開發者將分支部署到該命名空間,並在合併前運行完整測試套件。這些測試只有在針對真實數據運行時才最有價值。Snorkel 的生產數據庫是一個 Amazon Aurora PostgreSQL 集羣,而為每個 PR 命名空間提供該數據庫的獨立副本正是難點所在。此前恢復一份副本每個環境約需 20 分鐘,在開發者全天不斷提交 PR、合併隊列每次運行都需要全新環境的場景下,這樣的速度實在太慢。其他替代方案——共享預發佈數據庫、裁剪過的測試夾具或合成數據——又會重新帶來生產級測試本應解決的問題:測試之間相互干擾、模式過期,以及只有真實數據形態才會暴露的缺陷。
Snorkel 為 Lakebase 在 CI/CD 場景中的成功設定了明確的驗收標準。快速供給方面,新 PR 分支需在 60 秒內就緒(p95);規模方面,峯值時約需 100 個併發 PR 分支,每個分支都能獨立讀寫;兼容性方面,現有應用與 CI 套件需通過標準 Postgres 在 Lakebase 上運行,性能與 Aurora 相當,並支持大型 JSONB/LOB 列;數據新鮮度方面,主分支需通過持續的 DMS 複製保持與生產 Aurora 相差約 2 分鐘以內;安全性方面,生產數據須留在私有網絡內、絕不經過公共互聯網,開發者使用 Okta SSO 登錄,CI 流水線則以服務主體身份進行認證。
數據庫分支之所以契合 CI/CD,與 Lakebase 的架構特性直接相關。Lakebase 是 Databricks 的無服務器 Postgres 數據庫,其存儲與計算相互分離,並支持分支功能:可以像創建 Git 分支一樣,從任意時間點創建一個新的、隔離的、可寫的數據庫分支。分支採用寫時複製,創建分支只是一次元數據操作,創建時不會複製任何數據。新分支與父分支共享存儲頁,只有該分支修改過的頁才會被寫入為新的存儲。對於 CI 而言,這意味着創建分支只需數秒而非數分鐘,且與數據庫大小無關;存儲增長取決於每個分支產生的變更量,而非數據庫規模,Snorkel 的每個 PR 分支在約 1 TB 基礎數據之上大約寫入 5 至 10 GB 的變更;計算資源按分支分配並可縮容至零,每個分支擁有獨立的自動伸縮計算資源,在 CI 運行間隙會縮容至零,即便配置了 100 個分支,Snorkel 預計同時承載流量的也只有約 20 至 30 個,每個分支峯值時約每秒 5 次查詢。
整體架構分為四步。第一步,在主分支上保持一份新鮮的生產副本。Lakebase 是標準 Postgres,因此可以直接作為 AWS DMS 的目標,無需任何定製工具。Snorkel 將一個 DMS 任務指向其生產 Aurora 數據庫,並將其複製到 Lakebase 項目的主分支:先進行全量加載,再通過持續的變更數據捕獲使主分支與生產數據的延遲保持在約 2 分鐘以內。全 LOB 模式可完整搬運 10 至 20 MB 的 JSONB 值。由於團隊本就在運行 DMS,因此無需構建或維護新的複製流水線。主分支即每個 PR 分支的“黃金副本”。第二步,在 PR 打開時創建分支。開發者提交 PR 時,CI 流水線調用 Lakebase API 從主分支創建分支,為其設置過期時間,並將分支的連接信息傳入 PR 命名空間,分支在不到一分鐘內即可就緒。第三步,針對真實數據運行測試。PR 命名空間中的應用通過標準 Postgres 連接到其對應分支,測試可以運行遷移、寫入數據、修改模式,而不會影響生產、主分支或任何其他 PR。第四步,在 PR 關閉或測試通過後刪除分支,並以 TTL 作為兜底。PR 合併或關閉時,流水線會刪除該分支;若清理步驟未能執行,分支會在 TTL 到期後自行過期。
安全方面有兩項要求直接排除了其他方案,因此值得單獨説明。其一是私有連接:生產數據從 Aurora 遷移到 Lakebase、再從 Lakebase 傳到 CI 集羣,全程通過私有網絡而非公共互聯網。其二是身份認證:Snorkel 有兩類數據庫用户,一類是交互式連接以調試 PR 環境的開發者,另一類是在無人工介入下運行的 CI 流水線。由於 Okta SSO 圍繞交互式瀏覽器登錄設計,團隊按用户類型拆分設計:開發者方面,Okta 聯邦至 Databricks 賬户,用户通過 SCIM 配置,開發者使用其慣常的 Okta 身份登錄;CI 流水線方面,每個 PR 命名空間以 Databricks 服務主體(按團隊或按倉庫限定範圍)運行,同樣通過 SCIM 配置,PR Pod 使用服務主體憑據,通過 Databricks SDK 獲取短期的 Lakebase OAuth 令牌,並在長時間測試運行期間刷新令牌,CI 中不存在長期有效的數據庫密碼。審計方面,Postgres 審計日誌會記錄每次查詢對應的服務主體身份,因此每條查詢都可追溯到執行它的流水線。
寫時複製與分支過期這兩項特性共同保證了 CI 在大規模下既快又省。寫時複製讓分支即時可用:新分支不復制任何數據,而是指向父分支已有的存儲頁,只有被修改的頁才會寫入新存儲;從約 1 TB 的生產副本創建分支與從 1 GB 數據庫創建分支耗時相當,都是數秒,而非此前完整恢復所需的約 20 分鐘,每個 PR 命名空間都能立刻獲得一份隔離、可寫的生產數據副本。寫時複製也降低了分支成本:每個分支與主分支共享絕大部分數據,存儲隨每個分支產生的變更增長,而非隨數據庫規模增長,對 Snorkel 而言,即每個 PR 分支在共享基礎之上約增加 5 至 10 GB;計算按分支分配並在空閒時縮容至零,因此只有正在運行測試的分支才會佔用計算資源。分支過期則讓長期成本保持低廉:寫時複製在分支生命週期較短時收益最大,一個分支會保留其創建時的數據版本,隨着 DMS 持續向主分支寫入生產變更,長期存在的分支會一直持有那些較早的頁,其佔用的存儲也會隨時間增長;為每個 CI 分支設置 TTL,意味着每個分支在 PR 完成後會被自動移除,從而使存儲規模接近生產基礎數據加上活躍 PR 變更的水平。
同樣的模式也適用於 AI 智能體。需要生產數據一次性副本的工作負載不止 PR 命名空間,編寫 SQL、執行遷移或修改數據的 AI 智能體同樣需要一個安全的試驗場所,而寫時複製分支正好提供了這樣的環境。可以為每個智能體任務創建一條主分支的副本:智能體可以讀取真實數據、寫入數據,甚至修改模式,而不會觸及生產或任何其他智能體的工作;無論數據庫多大,創建分支都只需數秒,因此為每個任務創建分支是切實可行的。多個智能體可以並行運行:存儲只隨每個分支修改的頁增長,每個分支的計算在空閒時縮容至零,因此並排運行數十個智能體的成本大致相當於它們所做的變更,而非數十份數據庫副本。團隊可以審查智能體所做的更改,或直接丟棄:在將任何內容應用到生產之前,可以檢查智能體在其分支上改了什麼;如果結果不對,刪除分支即可,無需回滾任何內容。TTL 可以替智能體完成清理:智能體可能產生大量短生命週期分支,為每個分支設置過期時間可自動移除被放棄的分支,與 CI 分支的清理方式相同。智能體也可獲得限定範圍的身份:與 CI 流水線一樣,智能體可以以服務主體身份配合短期 OAuth 令牌運行,因此智能體執行的每條查詢都能在審計日誌中被追蹤。
在結果方面,供給時間從此前的 30 分鐘以上降至使用 Lakebase 後的 60 秒以內;規模上按約 2.5 TB 生產數據集、約 100 個併發 PR 分支進行設計;兼容性上,CI 套件在 Lakebase 上運行“沒有重大兼容性問題”,性能與 Aurora 相當;採用範圍已推廣至各團隊共 60 至 70 名開發者。一位開發者表示:“以前我們必須物理複製數據,這些複製作業耗時數小時,並且經常在各類 CI 平台(GitHub Actions、CircleCI 等)上遇到網絡及其他瓶頸。我們一直在尋找一種解決方案,能在數據離開我們的 VPC 時仍滿足我們的安全與合規要求。”
面向 Lakebase 分支在 CI/CD 中的最佳實踐包括:每個 PR 一條分支,且從持續同步的主分支創建;始終設置 TTL,將其視為必需項而非可選項,並與 PR 或測試運行的通常時長相匹配;需要更新數據時創建新分支而非保留舊分支,從主分支重新創建只需數秒;讓計算縮容至零,因為任一時刻大多數已配置分支都處於空閒狀態;流水線使用服務主體與短期 OAuth 令牌,人員使用 SSO;按分支監控存儲,以便及早發現長期存在的分支。對於希望讓每個拉取請求都擁有類生產數據庫的團隊,可以從 Lakebase 入手,並閲讀分支文檔,在 CI 流水線中配置分支過期。