实时端点从InService起到删除都按实例小时计费,无论是否有流量;-storage(EBS)和data processed是另外两项;周末开发环境不关和正式环境费用一样。
几乎每一起令人意外的 SageMaker 账单都有同一个成因,而它不是实例类型。实时 endpoint 从到达 InService 状态那一刻起就开始按实例计费,直到你删除它为止,无论是否有任何调用。这个计费项没有"空闲费率"也不支持缩容到零。以下所有内容都是关于证明"就是这个问题"以及决定如何处理。
三件独立的事情,搞混它们才是账单令人困惑的根源。
Instance hours。占主体的计费项。InstanceType × InitialInstanceCount × endpoint 存在的挂钟小时数。调用次数完全不参与这个计算。
Storage。挂载到每个托管实例上的 EBS 卷,按 GB-月计费,只要实例存在就持续计费。
Data processed。进出 endpoint 的字节数。通常只是四舍五入的误差,只有在传输大 payload 时才值得核查。
因为第一项不包含流量成分,一个整个周末都挂着的开发用 endpoint 与一个在相同硬件上持续提供服务的生产用 endpoint 费用是一样的。查看 Amazon SageMaker AI pricing 获取当前的每小时费率;费率因实例族和区域而异,本文有意不引用任何具体数字。
实例费率、实例族和区域可用性都会变化。在博文中看到的任何每小时数字——哪怕是最近的——都应视为估算值,需对照你所在区域的定价页确认。
在做任何改动之前,先确认托管是这笔费用的计费项。在 Cost Explorer 中筛选 SageMaker 服务并按 usage type 分组。托管类型的 usage type 包含 Host 并以实例类命名,所以像 USW2-Host:ml.g5.2xlarge 这样的条目就是托管实例小时的费用——这正是你要找的。Training、processing 和 notebook 的 usage type 是分开的,属于另一个问题。
然后按 resource 或 tag 分组来做归属。这就是为什么在创建 endpoint 时打 tag 很重要:没有 tag,包含六个托管费用的账单只能告诉你支出的结构,但无法告诉你哪个团队对它负责。用每月托管费用除以 730 小时再除以实例数量,就得到了一个有效的每小时费率,可以与官方费率对比——如果吻合,说明 endpoint 整月都在运行,这就是答案。
看到大额托管账单后的本能反应是换用更小的实例。先做测量,因为修复方案取决于 endpoint 是哪种错误——忽略数据的 resize 可能让延迟变得更糟而不是省钱。
四个指标,来自两个 SageMaker namespace。Invocations 和 ModelLatency 在 AWS/SageMaker 下;CPUUtilization、MemoryUtilization、GPUUtilization 和 DiskUtilization 在 /aws/sagemaker/Endpoints 下。两者都以 EndpointName 和 VariantName 为维度。
aws cloudwatch get-metric-statistics \
--namespace AWS/SageMaker \
--metric-name Invocations \
--dimensions Name=EndpointName,Value=my-endpoint \
Name=VariantName,Value=AllTraffic \
--start-time 2026-07-01T00:00:00Z \
--end-time 2026-08-01T00:00:00Z \
--period 3600 --statistics Sum
将一个月的 Invocations 按小时分辨率求和,然后数一下有多少个小时是零。这个单一数字通常就能定案。一个月 730 小时中有 600 个空闲小时的 endpoint 不是实例规格问题。
仔细阅读 CPUUtilization。AWS 文档说它是各核心利用率的加和,因此在一个四核实例上范围是 0–400%,读数 90% 意味着实例大约处于 22% 繁忙状态,而不是 90%。有人基于这个误读缩减了规格,然后困惑为什么延迟翻倍。MemoryUtilization 和 DiskUtilization 是普通的 0–100% 百分比;GPUUtilization 的计算方式与 CPU 相同,会乘以 GPU 数量。
三者都产生一个大额托管数字,但修复方法毫无共同点。
Idle endpoint。调用量低,利用率低,持续产生实例小时数。通常是某个为了评估而部署但从未删除的东西,或者是某个已关闭功能背后的 endpoint。这是迄今为止最常见的成因。
Over-provisioned endpoint。有真实流量,但利用率远低于实例提供的能力——往往是因为 InitialInstanceCount 为了发布峰值而设置,之后从未重新审视,或者因为 autoscaling 的 MinCapacity 是作为"安心毯"而非容量决策而设置的。
Endpoint sprawl。每个 endpoint 单独来看都合理;但总体不合理。这是 per-endpoint 调查会漏掉的那一种,ListEndpoints 就是为它而生的:列出每个区域的所有 endpoint 并检查每一个是否都有负责人。
aws sagemaker list-endpoints \
--query 'Endpoints[].{Name:EndpointName,Status:EndpointStatus,Created:CreationTime}' \
--output table
根据成因对症下药。粗略地按节省幅度排序:
删除无人调用的资源。删除 endpoint 停止实例小时费用;模型和 endpoint config 是元数据,不产生任何费用,所以删除的 endpoint 可以用同一 config 一步调用重建。这使得删除远比感觉上那样激进,对于一个月零调用的任何资源,这是正确的操作。
将间歇性流量移出实时托管。Serverless inference 按请求计费而非按小时计费。Asynchronous inference 确实可以将实例真正缩容到零——参见 SageMaker 上的 async inference,包括唤醒它所需的第二个扩展策略。两者都以延迟换取空闲小时费用的消除。
启用 autoscaling,设置诚实的下限。目标跟踪策略消除了峰值供应与平均负载之间的差距。它的价值由 MinCapacity 上限锁定,所以从 3 到 10 的策略比从 1 到 10 的策略节省少得多。
最后才是 right-size。在理解了利用率并正确读取之后,选择能容纳 p95 延迟的最小实例。这放在其他三者之后做,因为对于一个本不该存在的 endpoint 做 resize 只能节省删除它所节省费用的一小部分。
在任何操作之前值得做的比较是 against a hosted inference API,那里空闲小时费用按结构设计就是零,你按 token 付费。这不一定更便宜——在持续高吞吐下,饱和的实例通常胜出——但交叉点是真实存在的计算,取决于你的 duty cycle,而不是任何人的基准。Multigrid 是一个 LLM gateway,所以它位于那条线的 hosted-API 侧,并按模型和按团队报告 per-request 成本,这才是计算所需的那个数字。
无论你选择哪种方式,加一个预算报警,这样下一次意外是通知而不是账单;在创建时给每个 endpoint 打 tag,这样下一次调查从负责人开始而不是从 usage type 开始。
Autoscaling a SageMaker Endpoint
SageMaker Serverless Inference: Setup and Its Real Limits
When SageMaker Makes Sense Instead of a Hosted Model API