title: 在被驅逐中倖存:如何在 GKE 上建構可抵禦中斷的 AI 工作負載
published: true
description: 學習如何在 Google Kubernetes Engine(GKE)上建構可抵禦中斷的 AI 工作負載策略。
tags: kubernetes, ai, gke, googlecloud
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ht3q28btunq9lofna1k1.png

Use a ratio of 100:42 for best results.

published_at: 2026-05-20 20:22 +0000


你已經把所有事情都做對了。你已將龐大的模型訓練工作容器化,部署到 Google Kubernetes Engine(GKE),還巧妙地把它導向 Spot VM 節點池,節省高達 90% 的運算成本。

一切順利運作了 38 小時。接著,一位優先順序更高的隨需客戶需要容量,Google Cloud 回收了你底層的 Spot VM,而你的節點就此消失。

無論你是使用可搶占的 Spot VM 來省錢,還是利用 動態工作負載排程器(Dynamic Workload Scheduler, DWS) 來排隊取得稀缺的 GPU,你都是建立在短暫存在的運算資源之上。這些硬體終究會被拿走。若要在未承諾容量上成功執行關鍵 AI 工作負載,你的應用程式架構必須假設失敗是必然會發生的。

以下是一份在 GKE 上建構可被中斷工作負載的實用指南。

1. 接住警告

當 Google Cloud 回收 Spot VM 時,並不是直接立刻拔掉電源線。它會向底層節點發送一個 ACPI 訊號,開始關機流程。Kubernetes 會攔截這個訊號,並將其轉換為直接傳送給你執行中容器的 SIGTERM 訊號。

在 SIGTERM 與最終致命的 SIGKILL 之間,你有一段寬限期(非系統 Pod 最長可達 15 秒)。

你的應用程式必須明確監聽這個訊號。當接收到時,程式應立即停止接受新的批次,完成目前的迴圈,將所有記憶體中的資料寫入磁碟,並以 0(成功)的狀態碼結束。

以下是一個用 Python 接收此訊號的簡單範例:

import signal
import sys
import time

def handle_sigterm(signum, frame):
    print("Received SIGTERM. Initiating graceful shutdown...")
    # 1. 停止處理新資料
    # 2. 將記憶體資料寫入持久化儲存空間
    # 3. 儲存最後的檢查點
    print("State saved. Exiting cleanly.")
    sys.exit(0)

# 註冊訊號處理器
signal.signal(signal.SIGTERM, handle_sigterm)

# 你的主要訓練迴圈
print("Starting training loop...")
while True:
    # 訓練模型...
    time.sleep(1) 

2. 將檢查點外部化

如果你的容器死亡,裡面的本機檔案系統也會一併消失。為了在中斷後仍能存活,你必須定期將進度(模型權重、最佳化器狀態、epoch 計數器等)儲存到外部儲存位置。

Cloud Storage(GCS) 是 Google Cloud 上常見的解決方案。

  • 頻繁儲存: 決定檢查點儲存的間隔,平衡遺失工作的成本與寫入儲存空間的額外負擔。每個 epoch 儲存一次,或每隔幾千個 step 儲存一次都很常見,但仍需依你的需求而定。
  • 保持同區域: 確保你的 GCS bucket 與 GKE 叢集位於相同區域(例如 us-central1),以降低延遲並避免對外資料傳輸費用。
  • 續跑,不要重來: 容器啟動腳本首先應該做的事,就是檢查那個 GCS bucket。如果 bucket 中存在檢查點,就將其載入,並從那個精確步驟繼續執行。

3. 為冪等性而設計

「冪等性」聽起來很專業,但意思就是:做同一件事兩次,結果會和做一次一樣。

想像一個批次推論工作,它會讀取一張圖片、進行處理,然後將結果寫入資料庫。如果你的 Pod 在寫入資料庫之後的幾毫秒被搶占,但在能將任務標記為完成之前就中斷了,那麼重新排程後的 Pod 很可能會再次處理那張圖片。

如果你的資料庫只是單純地插入新列,那你現在就會得到非預期的重複資料。

若要建立冪等的管線:

  • 在資料庫中根據唯一辨識碼(例如圖片 ID)使用 UPSERT(更新或插入)操作。
  • 在花費昂貴的 GPU 運算之前,先檢查紀錄是否已經存在。

4. 為批次處理解耦工作佇列

如果你要在數千個檔案上執行大型批次處理或推論工作,不要寫一支單體式 Python 腳本去迭代一份靜態的 CSV 清單。如果節點在第 5,000 列時掛掉,要管理從哪裡重新開始的狀態會非常痛苦。

相反地,請將工作負載解耦:

  1. 發布工作: 將你的資料集拆分成離散訊息,並推送到像 Pub/Sub 這類訊息代理服務。
  2. 提取工作: 讓你的 Spot VM worker Pod 一次一筆,或小批量地(例如每次 10 筆)從佇列中拉取訊息。
  3. 確認完成: 只有在結果已安全儲存後,才向 Pub/Sub 傳送「ACK」(acknowledgment,確認訊息)。

如果 Spot 節點在推論途中被搶占,worker 就會在送出 ACK 之前死亡。經過短暫逾時後,Pub/Sub 會自動讓那則特定訊息再次可用。另一個仍存活的 worker Pod 會無縫接手。沒有資料遺失,也不需要人工介入。

重點摘要

在 Spot VM 這類短暫存在的運算資源上執行,不只是基礎架構選擇,更是一種設計選擇。透過處理終止訊號、積極將檢查點儲存到 GCS、確保操作具備冪等性,以及將佇列解耦,你就能在不犧牲可靠性的前提下,釋放巨大的成本節省,並善用稀缺的 GPU 資源池。


原文出處:https://dev.to/googlecloud/surviving-the-eviction-how-to-build-interrupt-resilient-ai-workloads-on-gke-5581


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝6   💬2  
340
🥈
我愛JS
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登