題幹與適用場景
一個無狀態服務運行在多個可用區,副本數會從 2 擴到 30。節點故障、擴縮容和滾動發布期間,團隊希望避免副本集中在一個故障域,同時不能因嚴格分布導致新版本完全無法調度。請設計 topologySpreadConstraints,並說明何時使用 DoNotSchedule、ScheduleAnyway 或反親和性。
面試官考察什麼
- 能否把「高可用」具體化為節點、可用區、區域等故障域目標。
- 能否正確解釋
maxSkew、minDomains、topologyKey和whenUnsatisfiable。 - 能否識別標籤選擇器、缺少拓撲標籤和小副本數帶來的邊界行為。
- 能否把調度約束、PDB、滾動更新、自動擴容和觀測放在同一方案中。
回答前要釐清的問題
- 可用區是否真的獨立供電、網路和容量?區域故障是否在本次目標內?
- 服務至少需要幾個副本才能承受一個故障域丟失?
- 調度失敗時是寧可等待、降低可用性,還是允許暫時偏斜?
- 工作負載標籤、節點拓撲標籤和預設約束是否由平台統一管理?
- 滾動更新期間舊版與新版是否共用同一個
labelSelector?
30 秒回答框架
我會先定義故障域和最小容量,再為節點與可用區分別設定分布約束。關鍵服務使用受控的 DoNotSchedule,普通或彈性服務使用 ScheduleAnyway 作為軟目標;maxSkew 約束同一選擇器在 eligible domains 間的差距,minDomains 防止可用域不足時誤判。上線前驗證標籤、擴縮容、滾動發布和單域故障,運行中監控每域副本數、Pending 時長、可用容量和 PDB 中斷預算。
分步驟深入解答
第一步:先定義故障域和容量目標
把節點、可用區、區域映射為不同 topologyKey。若服務要承受一個可用區故障,應至少在兩個以上可用區保留足夠副本;若副本只有 2,無法同時保證三個可用區均勻且任一域故障後仍有兩個健康副本。先寫出容量不變量,再決定約束強度。
第二步:選擇 maxSkew 與 minDomains
maxSkew 表示目標域與全域最小值之間允許的最大差距;DoNotSchedule 下超過差距會讓 Pod 保持 Pending。minDomains 用於表達至少需要多少個 eligible domain,避免域數量不足時把全域最小值按零計算。小副本服務應透過演練確認設定不會阻塞發布。
第三步:區分硬約束和軟約束
關鍵控制面或支付服務可以在可用區層使用 DoNotSchedule,把調度失敗暴露為容量告警;批處理或可延遲服務可用 ScheduleAnyway,讓調度器優先降低 skew 但允許暫時偏斜。硬反親和性適合簡單的「不要同域」規則,但多層拓撲和可觀測 skew 通常更適合拓撲分布約束。
第四步:保證選擇器和標籤可信
約束的 labelSelector 必須匹配實際 Pod 模板,否則新 Pod 可能被計算到錯誤集合。節點必須帶有穩定的 zone、region 和 hostname 標籤;缺少標籤的節點不會按該拓撲域參與評分。平台應在准入時檢查選擇器、標籤和預設約束,避免團隊複製失效 YAML。
第五步:聯動發布、PDB 與擴縮容
滾動更新要計算舊版、新版和 maxUnavailable 的疊加容量,避免更新過程中暫時違反故障域目標。PDB 只能限制自願中斷,不能替代跨域調度。自動擴容器應感知 Pending Pod 和各域容量,否則嚴格約束可能持續等待而不增加可用節點。
第六步:定義故障和降級動作
先演練單節點、單可用區和節點標籤丟失,再觀察新 Pod 是被拒絕、偏斜調度還是長時間 Pending。關鍵服務可以暫停低優先級發布、擴容健康域或切換唯讀模式;不能在生產中臨時刪除硬約束而不記錄風險。降級動作應版本化並可回滾。
第七步:用分布指標驗證結果
按工作負載、版本和拓撲域記錄副本數、skew、Pending 時長、調度失敗原因、可用容量、PDB 中斷和請求錯誤率。壓測應覆蓋副本從 2 到 30、域容量不均、滾動更新和自動擴容。目標是證明故障域丟失後剩餘容量滿足 SLO,而不是只證明副本落在不同節點。
高品質示範回答
我會把節點、可用區和區域作為三層故障域,先確定一個可用區丟失後仍需保留的最小副本數。服務 Pod 使用匹配模板標籤的 labelSelector,在 hostname 和 zone 層分別設定約束;關鍵服務的 zone 約束使用較小 maxSkew 與 DoNotSchedule,批處理使用 ScheduleAnyway。當 eligible domains 少於 minDomains 時觸發容量告警,而不是靜默接受錯誤分布。滾動更新同時校驗 PDB、maxUnavailable 和新舊版本選擇器,自動擴容器監聽 Pending 原因和域容量。上線先以觀測模式運行,隨後灰度啟用硬約束,並用每域副本數、Pending 時長、故障域演練結果和業務 SLO 作為回滾閘門。
常見錯誤
- 只寫「跨可用區部署」,卻沒有說明
topologyKey和副本容量。 - 把
maxSkew誤解成域之間的絕對副本上限。 - 忽略
labelSelector不匹配,導致約束統計了錯誤的 Pod 集合。 - 把 PDB 當成調度約束,或認為 PDB 能阻止所有節點故障。
- 對副本數為 2 的服務承諾三個可用區都均勻且任一域故障後不降級。
- 直接刪除
DoNotSchedule解決 Pending,卻沒有記錄可用性風險。
追問及應對
追問一:ScheduleAnyway 還有高可用價值嗎?
有。它把降低 skew 作為調度偏好,在容量不足時仍允許運行;適合可延遲或有其他冗餘的工作負載。關鍵服務可在高峰前擴容並使用硬約束。
追問二:為什麼不全部使用 pod anti-affinity?
反親和性表達「避免與某些 Pod 同域」,多層拓撲、skew 數值和最小域數量表達較弱。拓撲分布約束更直接描述跨域差距,反親和性仍適合單一排斥規則。
追問三:minDomains 配錯會怎樣?
eligible domain 數量不足時,skew 的全域最小值計算可能讓約束看起來滿足或使 Pod 長時間 Pending。應把域可用性納入准入檢查和容量告警,並在叢集版本上確認欄位行為。
追問四:滾動發布為什麼會破壞分布?
新舊版本可能使用不同標籤選擇器,或者 maxUnavailable 與 maxSurge 暫時增加某個域的副本。發布前應模擬中間狀態並觀察每個版本、每個域的 skew。
追問五:節點缺少 zone 標籤怎麼辦?
該節點不會按指定拓撲鍵正確參與分布。平台應修復節點標籤或隔離節點,不能把無標籤節點當成獨立故障域來承諾容量。
追問六:如何證明一個可用區故障後仍滿足 SLO?
執行隔離演練,確認剩餘域的可調度容量、健康副本、請求錯誤率和恢復時間滿足目標;同時記錄 PDB、Pending 原因和擴容時間,驗證從調度到業務指標的完整鏈路。