題幹與適用場景
這是節點控制面與執行時邊界的系統設計題。標準 CRI 的 ListContainers、ListPodSandbox 與 ListImages 是 unary RPC,一次回應全部結果;高密度節點的序列化結果可能超過 gRPC 預設 16 MiB 單一訊息上限,導致 kubelet 無法完成 reconciliation。Kubernetes v1.36 引入 alpha 特性閘 CRIListStreaming,讓 kubelet 使用伺服器串流 RPC 分批接收結果。題目要求同時處理吞吐、記憶體、相容回退與灰度風險。
面試官考察點
- 能否從單一訊息大小、序列化配置與重同步路徑解釋故障,而非只說「節點太大」。
- 能否區分
List串流傳輸與 watch/event 串流,保留 kubelet 的列表加後續事件一致性。 - 能否設計具回壓、取消、逾時與部分結果語意的消費端。
- 能否說明 alpha 特性預設關閉、執行時相容與自動回退的邊界。
- 能否給出灰度、指標、告警與回滾條件。
回答前需要釐清的問題
- 節點上的執行中、已停止容器與 sandbox 總數是多少,尖峰成長率如何?
- 使用的 container runtime 是否實作三個 streaming RPC,版本與升級窗口是什麼?
- 故障表現是單一訊息超限、kubelet 記憶體壓力,還是 runtime 建立列表過慢?
- reconciliation 是否允許短暫重試,哪些錯誤必須 fail closed?
- 可以先在獨立節點池開啟 alpha gate 嗎,回滾需要多久?
30 秒回答框架
「先確認 unary CRI 列表把所有物件放進一條 gRPC 訊息,數量達到約一萬時可能碰到預設 16 MiB 限制並形成記憶體尖峰。Kubernetes v1.36 的 CRIListStreaming 是預設關閉的 alpha gate;開啟後 kubelet 呼叫三個 server-side streaming RPC,runtime 分批回傳,消費端逐批更新暫存狀態。我要在支援該 RPC 的 runtime 與 canary 節點池灰度,限制緩衝、傳播取消並監控列表耗時、訊息大小、記憶體與重同步錯誤。runtime 不支援時會自動回退 unary,但高密度節點仍需告警,因為舊故障模式仍在。」
分步驟深入解答
第一步:定位單一訊息故障
Unary RPC 的回應包含完整列表,客戶端通常要經歷 protobuf 解碼、物件配置與狀態合併的峰值。gRPC 預設單一訊息限制約為 16 MiB;物件數量、欄位長度與映像名稱共同決定是否越界。約一萬容器只是經驗量級,不是協定閾值,應以實際物件大小、runtime 日誌與 kubelet 指標確認。
第二步:定義串流契約
啟用 CRIListStreaming 後,kubelet 使用 StreamContainers、StreamPodSandboxes 與 StreamImages。runtime 作為 server 端按批次傳送結果,客戶端每收到一批就解碼與合併,避免一條訊息承載全部資料。最終列表仍應形成一致快照,再接續原有 reconciliation 邏輯;串流 list 不等於 watch,也不會自動提供持續事件訂閱。
第三步:控制回壓、取消與失敗
客戶端應設定 deadline,限制未處理批次與物件緩衝;處理速度下降時暫停讀取或讓 runtime 感知流控。節點離開、同步版本過期或上層取消時要關閉 stream,避免洩漏 goroutine 與連線。中途斷流不能把部分列表當成完整成功結果:丟棄暫存快照並重試,或按明確 checkpoint 設計冪等恢復,最終再提交一次完整狀態。重試必須避免重複物件造成計數膨脹。
第四步:做相容灰度
先盤點 runtime 是否實作三個 streaming RPC,並在獨立節點池啟用 feature gate。runtime 不支援時 kubelet 會自動回退 unary,以保持舊版本相容;但回退不是容量修復,仍應標記節點能力並對高密度節點告警。灰度期間比較支援與回退節點的列表耗時、峰值 RSS、解碼佇列、斷流重試與 reconciliation 失敗率。
第五步:設計觀測與容量保護
至少記錄每次 list 的物件數、批次數、每批位元組、總耗時、首批耗時、stream 取消與重試原因。結合 kubelet 工作集、runtime CPU、連線數與節點壓力,觀察是否把記憶體峰值轉成更長處理時間。設定最大物件數、deadline 與 admission control;超限時返回可診斷錯誤,不能靜默截斷列表。成功標準是重同步完成且狀態完整,不是只看首批回傳很快。
第六步:回滾與升級邊界
alpha gate 預設關閉,開啟範圍應可按 kubelet 設定回滾。發現 runtime 崩潰、斷流率升高、列表一致性錯誤或記憶體未改善時,先關閉 gate 並重啟受影響 kubelet,再按 runtime 與 kubelet 日誌復盤。升級 runtime 時保留能力探測與回退路徑;只有多版本矩陣驗證通過後,才擴大節點池。
高品質示範回答
「我先把問題歸因到 unary CRI list 的單一訊息與物件配置峰值,而非簡單提高 gRPC 上限。Kubernetes v1.36 的 CRIListStreaming 是預設關閉的 alpha 能力;打開後 kubelet 使用三個 server-side streaming RPC,runtime 分批傳送容器、sandbox 與映像。客戶端逐批合併到暫存快照,設定 deadline、有限緩衝與取消;斷流時丟棄不完整快照並冪等重試,完成後才進入原有 reconciliation。灰度先驗證 runtime RPC 能力,再比較批次數、首批與總耗時、kubelet RSS、重試及狀態錯誤。runtime 不支援會自動回退 unary,但高密度節點必須告警,因為 16 MiB 與記憶體尖峰風險仍存在。任何一致性錯誤都先關閉 gate 回滾。」
常見錯誤
- 把 streaming list 當成 watch,遺漏列表快照與後續事件的邊界。
- 只調大 gRPC 訊息上限,忽略序列化與 kubelet 解碼記憶體峰值。
- 讀取所有批次前就提交 reconciliation,斷流後留下半套狀態。
- 認為自動回退等於問題已解決,沒有識別 runtime 不支援節點。
- 只測平均耗時,不測 RSS、批次大小、斷流重試與狀態完整性。
- 把約一萬容器說成固定觸發閾值,未結合物件大小與實際指標。
追問及應對
串流中途斷開時是否可以保留已收到物件?
預設不能把它當完整列表提交。應將批次寫入暫存快照,斷流後丟棄或按帶版本的 checkpoint 冪等恢復;只有協定明確提供完整性標記並完成校驗,才可提交。
runtime 只實作其中一個 streaming RPC 怎麼辦?
按能力逐項探測,未實作的方法繼續走 unary。記錄每個節點的能力標籤,並在高密度節點上告警;不要假設部分啟用會消除所有列表故障。
為什麼不直接把訊息上限調更大?
更大的上限只能延後單一訊息失敗,同時提高單次配置、複製與 GC 峰值,還可能放大 kubelet 與 runtime 的延遲尖峰。應優先使用分批串流協定,並用指標證明完整性與容量收益。