本章探討如何透過金絲雀部署(Canarying)來平衡發布速度與系統可靠性。金絲雀部署是指對服務進行部分且有時間限制的變更部署及其評估,幫助我們決定是否繼續完整推出。接收變更的部分稱為「金絲雀(Canary)」,其餘部分稱為「控制組(Control)」。金絲雀部署本質上是一種 A/B 測試流程。
發布工程原則#
發布工程(Release Engineering)涵蓋從程式碼庫到運行中生產系統的所有流程和產物。自動化發布能避免許多傳統陷阱:重複性手動任務的苦差事、非自動化流程的不一致性、無法得知推出的確切狀態,以及回滾的困難。
基本原則包括:
- 可重現建構(Reproducible Builds):相同輸入應產生相同輸出
- 自動化建構(Automated Builds):程式碼簽入後自動產生建構產物
- 自動化測試(Automated Tests):建構產物自動通過測試套件
- 自動化部署(Automated Deployments):由電腦而非人類執行部署
- 小型部署(Small Deployments):建構產物應包含小型、自包含的變更
這些原則帶來的具體好處:減少工程師的操作負擔、強制同儕審查和版本控制、建立一致可重複的流程減少錯誤、以及能夠監控發布管線並持續改進。

Figure 16.1: The virtuous cycle of CI/CD
CI/CD 加上發布自動化能為開發週期帶來良性循環:自動化發布讓你能更頻繁發布;對於有非瑣碎變更率的軟體,更頻繁發布意味著每次發布包含更少變更;更小的發布產物讓回滾更容易且成本更低;更快的發布節奏意味著錯誤修復能更快到達使用者手中。
平衡發布速度與可靠性#
發布速度和可靠性常被視為對立目標。在 Google 的經驗中,大多數事故是由二進位檔或組態推送觸發的。然而,這些變更(錯誤修復、安全修補、新功能)對業務成功是必要的。
正確做法不是反對變更,而是使用 SLO 和錯誤預算(Error Budget)的概念來衡量發布對可靠性的影響,目標是在滿足使用者期望的可靠性目標下盡快發布軟體。
分離不同變更速率的元件:服務由多個具有不同變更率的元件組成(二進位檔、環境、函式庫、服務組態、功能實驗組態等)。功能旗標(Feature Flag)框架允許將功能啟用與二進位發布分離,如果某些新功能表現不如預期,可以選擇性地停用這些功能。
什麼是金絲雀部署?#
「金絲雀」一詞源自將金絲雀帶入煤礦以判斷礦坑是否安全的做法。即使發布管線完全自動化,直到真實流量命中服務之前,你無法偵測到所有與發布相關的缺陷。測試環境不會 100% 等同於生產環境,測試也不會涵蓋 100% 的可能場景。
金絲雀部署允許部署管線以盡可能少的服務影響,盡可能快地偵測缺陷。
金絲雀流程的要求#
- 一種將金絲雀變更部署到服務子集的方法
- 評估金絲雀變更是「好」還是「壞」的評估流程
- 將金絲雀評估整合到發布流程中
直接部署 vs. 金絲雀部署#
無金絲雀的直接部署#
在沒有金絲雀流程的情況下,部署到生產環境後如果監控報告高錯誤率,且部署流程不提供回滾選項,唯一的選擇是在停機期間找到缺陷、修補並部署新版本,這幾乎肯定會延長使用者受影響的時間。

Figure 16.2: High rate of errors after deployment
使用金絲雀的部署#
透過金絲雀部署,不是一次部署到所有生產環境,而是建立一小部分生產環境運行候選版本,將少量流量導向該部分,並與控制組比較。

Figure 16.3: Error rate of canary deployment
使用金絲雀時,變更的影響大幅降低——錯誤在整體流量趨勢中幾乎不可見。這也帶來一個有趣的問題:金絲雀評估相較於整體流量趨勢更難觀察和追蹤。
要更清楚地看到需要追蹤的錯誤,可以按應用程式版本查看關鍵指標(如 HTTP 回應碼),這樣就能清楚看到新版本引入的錯誤。

Figure 16.4: HTTP response codes by App Engine version
金絲雀實作#
最小化對 SLO 和錯誤預算的風險#
金絲雀流程僅冒險使用錯誤預算的一小部分,受時間和金絲雀群體大小的限制。
以具體數字說明:如果直接部署會導致 20% 的請求失敗,改用 5% 的金絲雀群體,則只有 5% 的流量承受 20% 錯誤率,整體錯誤率僅為 1%。對錯誤預算的影響直接與暴露於缺陷的流量成正比。
這是一個假設均勻負載的簡化模型,也假設缺陷導致 100% 失敗率(最壞情況)。實際上,缺陷不太可能影響 100% 的使用。建議使用滿足技術和業務目標的最簡模型,過度追求技術正確性的複雜模型往往導致過度投資。
選擇金絲雀群體和持續時間#
選擇金絲雀持續時間時需考量開發速度:
- 每日發布:金絲雀不能持續一週
- 每週發布:可以執行較長的金絲雀
- 持續部署(例如一天 20 次):金絲雀持續時間必須顯著縮短
雖然可以同時運行多個金絲雀部署,但這會增加追蹤系統狀態的心智負擔,在非標準情況下可能變得棘手。同時運行的金絲雀如果重疊,還會增加訊號汙染的風險。強烈建議一次只運行一個金絲雀部署。
代表性金絲雀流程需要在多個維度做出決策:
- 大小和持續時間:應足夠大且持續夠久,以代表整體部署
- 流量量:需要足夠流量確保系統已處理代表性樣本
- 時段:效能缺陷通常只在高負載時顯現,離峰時間部署可能無法觸發
- 評估指標:代表性與所選評估指標緊密相關
選擇和評估指標#
指標應能指出問題#
建議以 SLI(Service Level Indicator)作為思考金絲雀指標的起點。好的 SLI 通常與服務健康有強烈的歸因關係。
選取前幾名的指標用於金絲雀評估(不超過約十幾個)。過多指標會帶來遞減回報,維護成本可能超過收益,如果未妥善維護還會對發布流程的信任產生負面影響。
以範例服務為例,最佳指標可能是 HTTP 回應碼和回應延遲,因為它們的降級最直接對應到影響使用者的實際問題。CPU 使用率等指標則較不適合:資源使用增加不一定影響服務,且可能導致金絲雀流程不穩定或產生雜訊。
HTTP 回應碼中存在棘手案例,如 404 碼可能源自使用者取得錯誤 URL。可以排除 400 級別的錯誤碼,並加入黑盒監控來測試特定 URL 的存在。
指標應具代表性且可歸因#
觀測指標變化的來源應可明確歸因於正在進行金絲雀測試的變更,不應受外部因素影響。
在大型群體中,可能存在異常值(超額訂閱的機器、不同效能特性的核心、過載的網路段等)。金絲雀群體與控制組之間的差異,既是我們部署變更的函數,也是兩個基礎架構差異的函數。
需注意金絲雀和控制組環境之間的共享故障域:壞的金絲雀可能負面影響控制組,反之亦然。指標隔離也很重要——例如,整體系統的 CPU 使用率劇增可能是其他程序造成的,更好的指標是服務請求所花的 CPU 時間。
前後比較評估的風險#
前後比較(Before/After)金絲雀流程是將舊系統完全替換為新系統,然後比較變更前後的行為。這種方式的問題在於:時間是觀測指標變化的最大來源之一,難以評估效能降級是否由金絲雀部署造成。
例如,週一發布可能將工作日行為與週末行為做比較,引入大量雜訊。
使用漸進式金絲雀以改善指標選擇#
可以使用包含多個階段的金絲雀:
- 第一階段:小型金絲雀,使用最清晰的問題指標(應用程式當機、請求失敗等),最小化負面影響
- 後續階段:更大的金絲雀群體,增加對變更影響分析的信心
依賴關係與隔離#
被測試的系統不會在完全真空中運行。金絲雀群體和控制組可能共享後端、前端、網路、資料儲存等基礎設施。甚至可能存在非常不明顯的互動——例如同一客戶端的連續請求分別命中金絲雀和控制組。
不完美隔離的後果:
- 金絲雀流程指出應停止變更並調查時,金絲雀部署不一定是罪魁禍首
- 金絲雀的不良行為可能負面影響控制組,造成 A/B 比較中兩者同時變化
- 使用絕對度量(如定義的 SLO)來確保系統正常運作非常重要
非互動式系統中的金絲雀#
對於非同步處理管線等非互動式系統,金絲雀的考量有所不同:
- 持續時間:取決於工作單元處理的持續時間,金絲雀持續時間至少應涵蓋單一工作單元的處理時間
- 隔離:在多階段管線中,應確保處理特定工作單元的 worker 始終從同一池(金絲雀池或控制組池)中抽取
- 指標選擇:可能關注端到端處理時間和處理品質
監控資料的要求#
進行金絲雀評估時,必須能比較金絲雀訊號與控制組訊號,這需要在監控系統中做細粒度的分解。
以 5% 金絲雀群體運行 20% 錯誤率為例,整體監控只會偵測到 1% 的錯誤率,可能無法與其他錯誤來源區分。但按服務請求的群體(金絲雀 vs. 控制組)分解指標,就能清楚觀察差異。
金絲雀部署在設計上是有時間限制的,這在指標以特定週期聚合時可能造成問題。例如,使用「每小時錯誤數」指標來評估僅 30 分鐘的金絲雀部署,可能因為包含部署前的不相關事件而給出混淆的訊號。確保指標的間隔等於或小於金絲雀持續時間。
相關概念#
藍/綠部署(Blue/Green Deployment)#
維護兩個系統實例:一個正在服務流量(綠色),另一個準備好服務流量(藍色)。切換不需要停機,回滾只是簡單地反轉路由器變更。缺點是使用兩倍的資源。可以透過同時使用藍綠兩個部署並慢慢分割流量,來實現類似 A/B 金絲雀的效果。
人工負載產生(Artificial Load Generation)#
使用人工負載而非真實使用者流量進行測試。人工負載擅長最大化程式碼覆蓋率,但無法提供良好的狀態覆蓋率。在可變系統(有快取、Cookie、請求親和性等)中尤其難以模擬,且在帳單系統等場景可能很危險。
流量鏡像(Traffic Teeing)#
複製流量同時發送到生產系統和測試環境。生產系統服務實際流量,金絲雀部署服務副本並丟棄回應。這可以提供代表性流量,但設置通常比直接金絲雀更複雜,且在有狀態系統中可能引入非預期的影響(例如共享快取導致快取命中率被人為膨脹)。
結論#
沒有單一測試方法是萬能的,測試策略應根據系統的需求和行為來決定。金絲雀可以是一種簡單、穩健且易於整合的方式來補充測試。及早發現系統缺陷可以將使用者影響降到最低,金絲雀也能為頻繁發布提供信心並提升開發速度。正如測試方法論必須隨系統需求和設計演進,金絲雀流程也是如此。