這篇 AWS 機器學習部落格討論了在 Amazon SageMaker AI 即時終端節點上使用 Application Auto Scaling 時,CloudFormation 或 AWS CDK 更新配置會失敗的常見問題。問題源於 SageMaker 的要求:在刪除終端節點變體或修改其例項型別前,必須先在 Application Auto Scaling 中登出對應的可擴縮目標;但一旦在 CloudFormation 之外手動登出,CloudFormation 就無法繼續跟蹤這些擴縮資源。
文章歸納了三種失敗情形。第一,如果可擴縮目標仍處於註冊狀態就修改終端節點配置,CloudFormation 會先嚐試更新端點,而 SageMaker 會拒絕操作,並提示 AllTraffic 變體必須先登出為可擴縮目標,之後才能移除或更新例項型別。第二,如果使用者透過 AWS CLI 手動登出目標,然後只修改終端節點配置,部署雖能成功,但 CloudFormation 不會重新註冊擴縮目標,也不會重新應用擴縮策略,因為模板中的擴縮引數沒有變化;結果是端點靜默失去自動擴縮能力。第三,如果手動登出後又修改擴縮引數,CloudFormation 會嘗試更新已不存在的 ScalableTarget 資源並報錯;更嚴重的是回滾也可能失敗,堆疊進入 UPDATE_ROLLBACK_FAILED 狀態,需要在控制台人工恢復。
解決方案是一個可複用的 CDK construct。它不再直接使用原生 AWS::ApplicationAutoScaling::ScalableTarget 和 ScalingPolicy 資源,而是用三個 CloudFormation 自定義資源,並透過 CDK 的 add_dependency 明確編排順序:先登出可擴縮目標,再由 CDK 更新終端節點,然後等待端點進入 InService 後註冊可擴縮目標,最後等待目標可查詢後附加目標跟蹤擴縮策略。首次部署時還沒有可擴縮目標,登出處理程序會捕獲 ObjectNotFoundException 並繼續。
註冊目標和附加策略採用 CDK provider 的非同步完成模式。每個自定義資源的 on_event 處理器立即返回,is_complete 處理器則由 provider 的 waiter 每隔約 30 秒重新呼叫,直到就緒檢查透過。Register Scalable Target 的總超時為 1 小時,Attach Scaling Policy 為 15 分鐘,因此等待不受單次 Lambda 呼叫超時限制。每個自定義資源還帶有 ConfigHash 屬性;只要端點配置或擴縮引數變化,CloudFormation 就會重新呼叫相關 Lambda。文章強調,端點配置和擴縮引數必須放在同一個 ConfigHash 中,因為一次雜湊變化會驅動整套擴縮編排。
部署後的堆疊並不只有三個 Lambda。每個自定義資源背後都有一個 CDK cr.Provider,provider 框架會生成輔助函式:同步 provider 的 Deregister 增加一個框架函式;非同步 provider 的 Register Scalable Target 和 Attach Scaling Policy 各增加 onEvent、isComplete、onTimeout 三個函式,並由 AWS Step Functions 狀態機驅動 waiter。因此,堆疊實際包含三個自定義資源、兩個 Step Functions 狀態機和十二個 Lambda 函式。其中五個資源承載 construct 自身的處理程式碼,另外七個由 provider 框架生成;這些函式無需使用者維護,但在審查部署資源時應計入。
文章給出了完整演練。使用者需要具備 SageMaker AI、Lambda、IAM、Application Auto Scaling 和 CloudWatch 許可權的 AWS 賬戶,安裝 AWS CDK v2、Python 3.12 或更高版本以及 uv,並準備 S3 中的模型構件和 ECR 映象,或使用 SageMaker 內建演算法容器。演練先克隆 GitHub 示例倉庫並執行 uv sync,然後在 config/config.yaml 中同時配置 endpoint 和 autoscaling。端點引數對應 CreateModel 和 CreateEndpointConfig API,擴縮引數對應 RegisterScalableTarget 和 PutScalingPolicy API。隨後執行 cdk bootstrap 和 cdk deploy InferenceStack,並用 describe-scalable-targets 與 describe-scaling-policies 檢查可擴縮目標和策略是否註冊成功。
更新測試只需修改 config/config.yaml,例如把例項型別從 ml.m5.large 改為 ml.m5.xlarge,再重新部署;部署完成後再次查詢,確認自動擴縮仍然註冊並反映新值。若已有 CDK 堆疊,可把 sagemaker_autoscaling/constructs/ 目錄複製到專案中,在端點資源旁例項化 SagemakerAutoscalingConstruct,並傳入端點、AutoscalingConfig 以及同時包含端點與擴縮引數的 config_hash。
實現細節方面,Deregister 自定義資源在端點更新前呼叫 deregister_scalable_target,並針對首次部署沒有目標的情況捕獲 ObjectNotFoundException;CDK 透過 endpoint.node.add_dependency(deregister) 建立依賴。Register Scalable Target 不能只依賴 CloudFormation 認為端點資源已完成,因為可擴縮目標必須在端點進入 InService 後才能註冊;因此它使用非同步完成模式,on_event 立即返回,is_complete 持續查詢端點狀態,若狀態為 Failed 則丟擲異常。Attach Scaling Policy 同樣等待可擴縮目標可查詢後再應用策略。原文在 Register 處理程序的條件檢查處被截斷,但上述編排邏輯和配置要點已經完整說明了方案。