01

總覽:新版本如何安全地接手流量

部署不是單純覆蓋二進位檔,而是控制「程式碼置換」與「真實流量放行」的時間差。

在單機時代,發佈新版本意味著停機、替換執行檔、重啟程序;一旦新版本存在記憶體洩漏或查詢退化,所有線上使用者會在同一秒同時撞上故障。在分散式系統中,部署策略(Deployment Strategies)的核心命題只有一個:如何讓新版本(v2)在不中斷服務的前提下接手流量,並且在發現缺陷時,把受影響的使用者比例(Blast Radius)與恢復時間(MTTR)壓到最低。

Build Artifact
不可變映像檔 v2
▸
Provision & Warm
部署運算節點並預熱
▸
Traffic Shifting
L7 權重或指標漸進切流
▸
Feature Toggle
執行期依條件開關新邏輯

現代持續交付將「部署(把程式放到機器上)」與「發佈(讓使用者看見新功能)」拆成獨立步驟,使回滾不再依賴漫長的重新編譯。

工程團隊在選擇部署策略時,本質上是在四個無法同時拉滿的維度之間做折衷:

  • 爆炸半徑(Blast Radius):若 v2 帶有嚴重臭蟲,第一時間會有多少比例的線上請求受損(1%、25% 還是 100%)?
  • 回滾速度(Rollback Speed):發現異常後,將流量完全撤回 v1 需要幾秒?是改一條路由規則,還是要等整批容器重新拉取映像檔並通過健康檢查?
  • 額外容量成本(Capacity Overhead):發佈期間需要多準備多少台機器?是僅多開 10% 的過渡節點,還是必須同時維持兩套 100% 規模的生產環境?
  • 多版本並存複雜度(Coexistence Complexity):當 v1 與 v2 在線上同時讀寫同一個資料庫與快取時,網路協定與資料表 Schema 是否會發生衝突?
關鍵Deployment(部署)≠ Release(發佈)

把容器映像檔推上生產環境稱為 Deployment(基礎設施層動作);將真實使用者的請求導向新程式碼路徑稱為 Release(業務層動作)。Rolling Update 將兩者綁在一起,機器一啟動就接客;Blue-Green、Canary 與 Feature Flag 則將兩者解耦,這正是高可靠度系統能做到「秒級止血」的根本原因。

一句話答法部署策略是「爆炸半徑、回滾速度、額外機器成本、新舊並存相容性」的四維折衷;越快回滾、越小爆炸半徑的方案,對雙倍容量或漸進路由控制面的要求就越高。
02

四大部署與發佈模式深度拆解

從原位分批替換的 Rolling,到雙環境切換的 Blue-Green、按比例試水的 Canary,再到應用層的 Feature Flag。

1. Rolling Update(滾動更新)

Rolling Update 是最普及的預設策略。系統將現有叢集分成多個批次(Batch),每次停掉一小批 v1 實例、換上 v2 實例,待新實例通過 Readiness Probe 後再推進下一批。在容器編排篇(container-orchestration)中談過 Kubernetes Deployment 透過 maxSurge 與 maxUnavailable 控制滾動步調;在 AWS EC2 Auto Scaling 或 ECS 中,則對應 Rolling update with additional batch。

  • 優勢:額外容量成本極低(僅需 10%~25% 的 Surge 緩衝),不需要額外的 L7 權重路由控制面。
  • 致命傷:回滾也是滾動的。當部署推進到 60% 才發現異常,回滾必須反向執行另一輪滾動替換,期間必須等待連線排空(Connection Draining)與容器冷啟動,耗時往往長達數分鐘。

2. Blue-Green Deployment(藍綠部署)

藍綠部署直接避開「原位替換」的混亂:線上正在服務 100% 流量的舊環境稱為 Blue(v1);發佈時,平行建立一套規模完全相同(100% 容量)的全新環境 Green(v2)。工程師可以在 Green 環境上先跑合成測試(Synthetic Testing)與預熱,確認無誤後,在負載平衡器或 DNS 層將流量一次性從 Blue 切往 Green。

  • 優勢:零新舊版本混跑窗口(若一次性切流),且回滾速度極快——只要原來的 Blue 環境還沒銷毀,切回舊 Target Group 只需毫秒到數秒。
  • 致命傷:發佈與觀察期間需要 200% 的運算容量;若服務本身帶有龐大的本機狀態或需要維持數百萬條長連線(如 WebSocket 篇談到的有狀態閘道),一次性全量切換會引發連線瞬間重連風暴。

3. Canary Deployment(金絲雀發佈)

礦工下坑時會帶一隻對瓦斯極為敏感的金絲雀來預警危險。Canary 發佈只先部署極少數的 v2 實例(或利用 L7 路由權重切出 1%~5% 的真實流量),讓極小部分真實請求替全體使用者「踩雷」。待觀察一段時間(Baking Period)確認錯誤率與延遲沒有劣化,才按 5% → 25% → 50% → 100% 階梯推進。

  • 優勢:爆炸半徑被嚴格限制在首波比例(例如 2%),同時只需額外準備極少量的金絲雀實例容量。
  • 致命傷:新舊版本並存時間最長(可能持續數十分鐘至數小時),對資料庫 Schema 與 API 向後相容的要求最嚴苛;且必須搭配細粒度的 L7 流量控制與自動化指標觀測。

4. Feature Flag(功能旗標 / 暗發佈)

前三種策略都在「基礎設施或路由層」切換實例,而 Feature Flag 則把切換點搬進應用程式碼內部(if (flags.isEnabled("new-checkout", userContext)))。v2 程式碼可以透過 Rolling 或 Canary 先部署到所有機器上(此時新功能預設關閉,稱為 Dark Launch),之後再透過遠端組態中心(如 AWS AppConfig、LaunchDarkly)針對特定內部員工、特定地區或 1% 付費戶動態打開。

評估維度 Rolling Update Blue-Green Canary Feature Flag (結合部署)
額外容量需求 低(+10%~25% 批次緩衝) 高(+100% 雙倍平行環境) 極低(+1%~10% 金絲雀節點) 無額外機器(記憶體內判斷)
最小爆炸半徑 首個批次比例(約 10%~25%) 100%(一次性切流時) 1%~5%(可按權重微調) 單一 User ID / 內部測試員
回滾速度 (MTTR) 慢(2~10 分鐘,需重跑滾動) 極快(數秒,切回舊環境) 極快(數秒,權重歸零) 即時(毫秒~秒,推播組態)
新舊版本並存期 中(滾動進行的數分鐘內) 極短(僅切換瞬間之排空期) 長(整個各階觀察期) 長(新舊分支長期並存於同程序)
控制面依賴 基本健康檢查 (Readiness) Target Group / 路由切換 L7 權重路由 + 指標監控 低延遲組態推播 + 旗標生命週期清理

四大策略並無絕對優劣:Blue-Green 用雙倍機器買「零並存與秒級回滾」,Canary 用長並存期與控制面複雜度買「極小爆炸半徑與低機器成本」。

一句話答法Rolling 省機器但回滾慢;Blue-Green 回滾快但花雙倍容量;Canary 兼顧省容量與小爆炸半徑但拉長新舊並存期;Feature Flag 則將業務發布從部署管線中徹底解耦。
03

新舊版本並存:API 與 Schema 相容 (Expand / Contract)

只要線上同時存在 v1 與 v2 實例,任何破壞性 Schema 變更都會讓「秒級回滾」變成災難。

在面試中,許多候選人談完「用 Canary 切 5% 流量,出事就秒切回 v1」便以為萬無一失,卻忽略了背後的狀態層:運算實例是無狀態且可並存的,但底層資料庫通常只有一份。

假設你要將使用者資料表的 full_name 欄位拆成 first_name 與 last_name。若在部署 v2 前直接執行 ALTER TABLE DROP COLUMN full_name,線上仍在處理 95% 流量的 v1 實例會立刻因為找不到欄位而全面崩潰;反之,若 v2 寫入了只有 v2 看得懂的格式,當 Canary 失敗回滾到 v1 時,v1 讀到這批新資料也會反序列化失敗。

平行演進模式:Expand and Contract(擴張與收縮)

為了讓 Rolling 與 Canary 在任意時刻都能安全推進或無損回滾,資料庫與有狀態 Schema 必須遵循 Expand → Migrate (Dual-Write) → Contract 三階段演進,將一次破壞性變更拆成多次向後相容(Backward-compatible)與向前相容(Forward-compatible)的小步部署:

演進階段
資料庫 Schema 狀態
線上應用程式行為
回滾安全性
1. Expand
(擴張期)
新增可為 NULL 的 first_name、last_name,保留舊欄位 full_name(不加 NOT NULL 約束)。
線上仍為 v1(只讀寫 full_name),正準備透過 Canary 推進 v2。
完全安全:新欄位對 v1 透明。
2. Dual-Write
(雙寫與回填)
新舊欄位並存;背景批次工作(Backfill Job)掃描歷史舊列,補齊空白的新欄位。
v2 上線:同時寫入新舊欄位(Dual-Write);讀取時優先讀新欄位,若為空則 Fallback 讀舊欄位。
可隨時切回 v1:因 v2 仍持續同步寫入 full_name,v1 不會漏讀任何新異動。
3. Cutover
(讀取切換)
確認歷史回填 100% 完成,所有資料列的新舊欄位皆有值。
v3 上線:完全改讀新欄位,並停止讀取舊欄位(若確定不再回滾至 v1,可停止雙寫舊欄位)。
退回 v2 安全;若停止雙寫則不可再退回遠古 v1。
4. Contract
(收縮清理)
確認線上已無任何實例引用 full_name 後,執行 DDL 移除舊欄位並加上約束。
所有實例均穩定運行於 v3。
遷移閉環完成,消除技術債。

Expand / Contract 的核心紀律:永遠不在同一次應用程式部署中「同時新增新欄位並刪除舊欄位」;刪除動作必須留到所有舊版實例徹底退場且不再需要回滾之後。

陷阱訊息佇列與快取的「跨版本汙染」

除了關聯式資料庫,非同步佇列(Kafka / SQS)與共用快取(Redis)也是常見的回滾殺手。若 v2 Producer 發出了刪減欄位的訊息,線上並存的 v1 Consumer 就會解析失敗;若 v2 往 Redis 寫入新版序列化物件,切回 v1 後會引發整片快取反序列化崩潰。務必維持合約的加法演進(Additive Changes),或為破壞性快取鍵加上版本前綴(關於 API 契約演進與版本化規則,由 api-design-styles 專門討論)。

一句話答法有狀態變更必須走 Expand / Migrate / Contract:先加可空新欄並雙寫回填,等舊版實例 100% 下線且過完觀察期,最後才在獨立步驟中刪除舊欄位。
04

自動指標判定與漸進式交付 (Automated Canary Analysis)

不用人眼盯大盤:用黃金訊號、最小樣本數門檻與雙基線比對,讓部署管線自動推進或熔斷回滾。

如果 Canary 發佈後需要工程師守在螢幕前肉眼盯著 Grafana 儀表板 30 分鐘,那它既無法規模化,也容易因人為疲勞而漏看尾端延遲(Tail Latency)劣化。現代漸進式交付(Progressive Delivery)將流量切換與自動指標分析(Automated Canary Analysis, ACA)綁成閉環控制系統。

sequenceDiagram
    participant CD as 部署控制面
    participant LB as L7 路由器
    participant Can as Canary (v2)
    participant Met as 指標分析引擎
    CD->>LB: 1. 設定權重 v1=95%, v2=5%
    LB->>Can: 2. 導流 5% 真實請求
    Can-->>Met: 3. 上報 5xx / p99 延遲 / 飽和度
    Met->>CD: 4a. 指標異常 (超越閾值)
    CD->>LB: 4b. 緊急回滾:v2 權重歸 0%
    Met->>CD: 5a. 觀察期通過且樣本充足
    CD->>LB: 5b. 推進下一階:v2=25% -> 50% -> 100%
  

漸進式交付閉環:每一階權重提升後都必須通過「最小樣本數」與「觀察期(Baking Period)」雙重驗證,任一指標違規即自動將 v2 權重歸零。

自動判定時的三個工程細節

  1. 拿什麼比:絕對閾值 vs 對照基線(Baseline vs Canary):單純設定「5xx 錯誤率 < 1%」很容易在離峰或外部第三方故障時誤判。標準作法是同時建立一個與 Canary 同規模、同時間啟動的 v1 對照組(Baseline),計算 Canary 與 Baseline 之間的統計差異(如 Mann-Whitney U 檢定或相對退化比例)。這樣既能排除「剛啟動時的快取冷卻效應」,也能濾掉「全站外部依賴抖動」造成的假警報。
  2. 看哪些指標:四大黃金訊號 + 業務漏斗指標:除了 HTTP 5xx 錯誤率與 p95/p99 延遲,還必須納入業務層轉換率(例如結帳成功率、發文成功數)。因為如果 v2 把原本該正常處理的請求錯誤地直接回傳 200 OK 空陣列,基礎設施指標會看起來「又快又沒錯」,只有業務指標驟降才能抓出這類靜默壞死(Silent Failure)。(關於黃金訊號、SLO 與 Error Budget 的嚴格定義,由 slo-sli-alerting 負責)。
  3. 何時才算數:最小樣本數(Minimum Sample Size)與觀察期:在低流量時段,5% 的金絲雀可能在 5 分鐘內只收到 8 個請求,其中 1 個偶發逾時就會讓錯誤率飆到 12.5% 觸發假回滾;反之,記憶體洩漏(Memory Leak)或連線池耗盡往往需要累積數十分鐘才會顯現。因此 ACA 必須同時要求「Baking 時間達標」且「累積請求樣本數 N 足夠」。
AffectedRequests = TotalQPS × CanaryWeight × (DetectionWindowSec + RollbackSec)

上式揭示了 Canary 的真實保護力:即便把回滾時間 RollbackSec 壓到 3 秒,如果偵測窗口 DetectionWindowSec 需要 300 秒才湊得齊統計顯著樣本,期間仍會有 TotalQPS × CanaryWeight × 303 筆請求受損。這也是為什麼高風險變更常先用 Shadow Traffic(流量鏡像 / Dark Traffic)將真實請求複製一份非同步打向 v2(丟棄 v2 回應、不影響真實用戶),或者先用 Feature Flag 限縮在內部帳號驗證,確認無誤後才進入 Canary 權重切流。

一句話答法自動金絲雀分析(ACA)靠「同規模 Baseline 對照」消除冷啟動與時段偏差,並結合「黃金訊號 + 業務指標 + 最小樣本數門檻」決定自動推進或秒級歸零。
05

雲端實戰對照:AWS CodeDeploy / ALB / Lambda vs GCP Cloud Deploy / Cloud Run

不同運算層的流量切換原語:從 L7 Target Group 權重、Lambda Alias 到 Cloud Run Revision 流量分割。

在系統設計面試中,考官常追問:「你說用 Canary 切 10% 流量,在雲端架構上到底是哪一個元件在切?」不同運算模型(EC2/ECS、Kubernetes、Serverless)對應的流量控制點截然不同:

AWS 部署與切流原語 (CodeDeploy / ALB / Lambda)

1. ALB Weighted Target Groups:在單一 Listener 規則下掛載 Blue 與 Green 兩個 Target Group,直接調整路由權重(如 90:10),支援啟用 Stickiness 避免同一用戶在單次操作中反覆橫跳於 v1/v2。
2. AWS CodeDeploy:原生支援 EC2/On-Premises、ECS 與 Lambda 三種運算平台。在 ECS 藍綠/金絲雀部署中,CodeDeploy 會建立 Replacement Task Set,掛上測試埠驗證後,再依 Canary10Percent5Minutes 或 Linear10PercentEvery3Minutes 動態改寫 ALB 權重;期間綁定 CloudWatch Alarms,一旦告警觸發即自動中止並把權重切回 Original Task Set。
3. Lambda Alias Traffic Shifting:Lambda 每次發布會產生不可變的數字版本(Version 1, 2);穩定名稱的 Alias(如 prod)可在兩個版本間配置權重(例如 95% 指往 v1、5% 指往 v2),由 CodeDeploy 自動推進並執行 PreTraffic / PostTraffic Hook 驗證。

GCP 部署與切流原語 (Cloud Deploy / Cloud Run / GKE)

1. Cloud Run Revision Traffic Splitting:每次部署自動建立不可變的 Revision(如 svc-00001、svc-00002)。可直接在服務層按百分比分配流量(如 --to-revisions=svc-00002=10,svc-00001=90),或為新版綁定專屬 URL Tag(https://canary---svc.run.app)供內部先行壓測(0% 公開流量,100% 標籤存取)。
2. GCP Cloud Deploy:託管的持續交付管線,原生支援 GKE、Cloud Run 與 Anthos,內建 Canary 階段定義(如 percentages: [10, 50])與 Verify Job 自動驗證。
3. GKE / Kubernetes 進階切流:原生 K8s Service 只能按 Pod 數量比例分流(要切 1% 至少得開 100 個 Pod);細粒度百分比切流需搭配 Gateway API(HTTPRoute 的 backendRefs.weight)或 Argo Rollouts / Flagger 結合 Cloud Monitoring 自動推進。

容器與無伺服器平台的不可變版本(ECS Task Set、Lambda Version、Cloud Run Revision)讓權重切流與秒級回滾成為內建原語,不再需要手動搬移機器。

關鍵連線排空 (Connection Draining / Deregistration Delay) 的隱形時間窗

無論在 ALB 切換 Target Group 還是用 Rolling 替換實例,「路由權重變成 0%」只代表不再派發新請求,正在舊實例上執行中的長請求(In-flight Requests)仍會繼續跑完,直到超過 Deregistration Delay(ALB 預設 300 秒)才強制斷線。這意味著即使切流只需 1 秒,舊程式碼對資料庫的寫入仍可能持續數十秒——這再次印證了第 3 節 Expand / Contract 相容性的必要性。

一句話答法AWS 靠 ALB Weighted Target Groups、Lambda Alias 搭配 CodeDeploy + CloudWatch Alarms 實現自動漸進切流;GCP 則以 Cloud Run Revision Traffic Splitting、Gateway API 與 Cloud Deploy 對齊相同能力。
06

互動決策器:部署策略與爆炸半徑試算室

設定回滾時間要求、額外容量預算、Schema 變更性質與觀測成熟度,即時推導最佳部署組合並量化各方案的受影響請求數。

互動決策器 · 部署策略選型與受損請求評估 調整四個架構約束與線上流量參數,比較四種策略的合規性與故障衝擊

請回答下方 4 個系統約束問題,並透過滑桿設定線上流量(QPS)與預期故障率。決策引擎會先淘汰違反硬約束(容量上限、回滾 SLA、破壞性 Schema 變更)的策略,再從合格候選中選出衝擊最小的組合架構。

Q3. 額外容量預算上限 (Surge Cap) +25%
發佈期間可額外開啟的機器比例(Blue-Green 需 100% 雙倍環境)。
Q4. 權重路由與自動指標成熟度 L7 權重 + 自動告警
決定能否支援細粒度 Canary 切流與執行期旗標秒關。
線上總流量 (Total QPS) 2,000 req/s
用於計算發佈缺陷版本時,從暴露到完成回滾之間的受損請求總數。
新版本缺陷錯誤率 (Defect Rate) 5%
假設 v2 上線後帶有此比例的請求失敗,觀察各策略能擋下多少災情。
建議策略計算中… --

--

Rolling Update--
回滾耗時-- 額外容量-- 首波暴露-- 受損請求--
--
Blue-Green--
回滾耗時-- 額外容量-- 首波暴露-- 受損請求--
--
Canary (漸進)--
回滾耗時-- 額外容量-- 首波暴露-- 受損請求--
--
Canary + Flag--
回滾耗時-- 額外容量-- 首波暴露-- 受損請求--
--
首選策略 (合格且衝擊最低) 次選可行方案 違反約束出局
--
一句話答法面試收尾公式:基礎設施層用 Canary(或容量充裕時用 Blue-Green)控制運算實例切換風險,資料層強制執行 Expand / Contract 維持雙向相容,高風險業務邏輯再包一層 Feature Flag 做到秒級無損開關。