调用指标在AWS/SageMaker命名空间(Invocations、ModelLatency等),主机资源在/aws/sagemaker/Endpoints(CPUUtilization、GPUUtilization等);两者混淆是选型错误的根本原因。
SageMaker 会发布端点遥测数据,分布在两个 CloudWatch 命名空间下,先搞清楚哪个指标落在哪里能省不少时间。调用相关指标位于 AWS/SageMaker 命名空间,包括 Invocations、InvocationsPerInstance、ModelLatency、OverheadLatency、Invocation4XXErrors 和 Invocation5XXErrors。主机资源指标位于 /aws/sagemaker/Endpoints 命名空间,包括 CPUUtilization、MemoryUtilization,以及 GPU 实例上的 GPUUtilization 和 GPUMemoryUtilization。AWS 文档对这两个命名空间都有说明。
四个指标决定了实例规格的选择。Utilization 反映你使用了多少实例资源;InvocationsPerInstance 反映每个实例承载的吞吐量;ModelLatency 反映容器是否跟得上请求节奏;OverheadLatency 则将模型自身耗时与 SageMaker 围绕它所做的所有工作区分开来——这正是区分模型慢还是端点慢的关键。
aws cloudwatch get-metric-statistics \
--namespace /aws/sagemaker/Endpoints \
--metric-name CPUUtilization \
--dimensions Name=EndpointName,Value=my-endpoint \
Name=VariantName,Value=AllTraffic \
--start-time 2026-07-14T00:00:00Z \
--end-time 2026-08-11T00:00:00Z \
--period 3600 \
--statistics Average Maximum
第一个是 CPUUtilization。AWS 文档说明它是所有核心的累加值,因此在四核 vCPU 实例上,范围是 0% 到 400%,而不是 0% 到 100%。在这种实例上读到 150% 并不代表灾难性的过载,只相当于整机的 37.5%。如果团队把它解读为占整个实例的百分比,就会得出已经饱和需要升级的错误结论,走向了完全相反的方向。GPUUtilization 在每个 GPU 上也是如此:四 GPU 实例的范围是 0% 到 400%。
第二个是 ModelLatency,AWS 文档说明其单位是微秒。如果某个仪表盘把它标注为毫秒,就会出现千倍的偏差——而且偏偏是让一切看起来都很正常的方向。一个耗时 200 毫秒的模型会被显示为 200 微秒,没有人会去调查。在信任任何延迟面板之前,先检查一下单位。
这两个问题都不是什么隐晦的推论,都明明白白写在文档里。之所以要再次强调,是因为它们是实例规格优化过程中最常导致自信地得出错误答案的两个原因。
拉取至少两周的每小时 Average 和 Maximum 数据,针对绑定瓶颈的利用率指标(GPU 服务模型用 GPU 利用率,其他用 CPU 利用率),以及同一时间窗口内的 InvocationsPerInstance。
将利用率数据按核心数或 GPU 数归一化,这样你是在讨论实例的一部分,而不是原始百分比。
取峰值,而不是平均值。实例必须撑过两周内最繁忙的那个小时,而对有日规律的负载取均值会完全掩盖那个小时。
将峰值归一化利用率与当前实例和候选实例之间的比值进行比较。从四 vCPU 实例迁移到双 vCPU 实例大致会使利用率翻倍,因此峰值低于当前实例的约 35% 是进行该迁移的粗略前提——还要留出余量。
单独检查内存。内存是一堵硬墙而非渐变曲线:一个能装进 16 GB 但装不进 8 GB 的模型,在更小实例上不是跑得更慢,而是根本加载不了。
实例大小与吞吐量之间的关系在模型服务场景下并非线性。批处理行为、容器内部的线程池大小以及内存带宽都会使其弯曲,这就是为什么上面的算术只是候选筛选条件,而不是最终答案。
与其自己推演候选实例,不如让 SageMaker 对它们进行负载测试。CreateInferenceRecommendationsJob 会在一组实例类型上运行你的模型,并返回每个候选的 InstanceType、InitialInstanceCount、调优后的 EnvironmentParameters,以及指标 MaxInvocations、ModelLatency、CostPerHour 和 CostPerInference。AWS 文档说明默认任务最长需要约 45 分钟。API 参考在此。
CostPerInference 是整个过程追逐的数字,也是最常与直觉相矛盾的指标:一个更大的实例如果能按比例承载更多请求,其每次推理成本可能比小实例更低,最便宜的每小时费率往往不是最便宜的端点。先看这一列,再看每小时的那列。
有两个限制值得了解。任务本身会配置实例,因此不是免费的,所以把它当作周期性练习而非持续性练习。而且它用你提供的流量进行负载测试,因此推荐结果只和你提供的样本 payload 一样有代表性——喂给它真实的请求,包括那些耗时长的。
降规格是通过创建新的端点配置并调用 UpdateEndpoint 来实现的,它执行的是托管式 rollout,而不是停止再启动。整个过程中端点持续提供服务,你可以通过更新到之前的配置来回滚。
aws sagemaker create-endpoint-config \
--endpoint-config-name my-endpoint-cfg-smaller \
--production-variants '[{
"VariantName": "AllTraffic",
"ModelName": "my-model",
"InitialInstanceCount": 2,
"InstanceType": "ml.g5.xlarge"
}]'
aws sagemaker update-endpoint \
--endpoint-name my-endpoint \
--endpoint-config-name my-endpoint-cfg-smaller
然后观察正确的统计指标。平均 ModelLatency 在适度额外压力下几乎不动;p99 先动,而下游超时正是针对 p99 设置的。在更新之前就在 p99 上设置 CloudWatch 告警,而不是之后,这样有突破就能被告警捕获,而不是靠工单。
再观察两件事,完整走一个流量周期。降规格后 Invocation5XXErrors 上升,通常意味着容器现在在负载下撞到了内存或并发限制,而不是直接失败。OverheadLatency 应该不受实例大小影响——如果它动了,那就是除了实例之外还有其他东西变了。
最后,实例规格优化是退而求其次的选择,最好是根本不运行这个端点。每天只有少量请求的端点应该考虑 serverless inference 或者直接删除,而不是换成稍微小一点的实例——被遗忘的端点页面讲的就是这种情况。
Why a Forgotten SageMaker Endpoint Is a Common Surprise Bill
Why an Idle GPU Node Pool Costs More Than It Looks Like
The Quarterly Capacity Review