SageMaker本身不负责扩缩容,由Application Auto Scaling服务实现,需手动构造resource ID(endpoint/NAME/variant/VARIANT)并注册可扩展目标、定义策略、注册,三步完成。
SageMaker 终端节点不会自行扩缩容。扩缩容由 Application Auto Scaling 执行,这是一个与模型毫无关系的独立服务,整个配置过程只需要对着一个需要手动构造的资源 ID 调用三个 API。
Autoscaling 只需三个 API
注册一个可扩展目标、定义一条策略、应用它。前两个是容易踩坑的地方。需要注意的是这里是 Application Auto Scaling 而不是 SageMaker,这解释了为什么权限与你终端节点的权限毫无关联,以及为什么资源是用字符串而非 ARN 来寻址的。
调用方需要 sagemaker:DescribeEndpoint、sagemaker:DescribeEndpointConfig、sagemaker:UpdateEndpointWeightsAndCapacities,以及 application-autoscaling 相关操作、CloudWatch 告警操作,还有 iam:CreateServiceLinkedRole(对应 AWSServiceRoleForApplicationAutoScaling_SageMakerEndpoint)。最后这个是注册失败时人们最容易遗漏的——报错会提示权限错误但不会指明明显对应的资源;AWS 在其自动扩缩容前置条件页面上列出了完整策略。
注册可扩展目标
资源 ID 格式为 endpoint/NAME/variant/VARIANT,可扩展维度是 sagemaker:variant:DesiredInstanceCount。两者都是字面字符串;variant 名称来自你在 ProductionVariants 中设置的值,如果你沿用了 SDK 的惯例那就是 AllTraffic,否则就是你自己起的名字。
注册该 variant,并选择你愿意承担费用的上下界。MinCapacity 是实时终端节点上你需要持续付费的下限,所以要把它当作容量决策而非安全余量来考虑。
import boto3
aas = boto3.client("application-autoscaling")
resource_id = "endpoint/tenant-scorers/variant/AllTraffic"
aas.register_scalable_target(
ServiceNamespace="sagemaker",
ResourceId=resource_id,
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
MinCapacity=2,
MaxCapacity=10,
)
注册该 variant,并选择你愿意承担费用的上下界。MinCapacity 是实时终端节点上你需要持续付费的下限,所以要把它当作容量决策而非安全余量来考虑。
应用目标追踪策略到预定义指标
AWS 在"定义扩缩容策略"页面上的官方示例将每个实例的平均调用次数维持在 70。
aas.put_scaling_policy(
PolicyName="invocations-per-instance",
ServiceNamespace="sagemaker",
ResourceId=resource_id,
ScalableDimension="sagemaker:variant:DesiredInstanceCount",
PolicyType="TargetTrackingScaling",
TargetTrackingScalingPolicyConfiguration={
"TargetValue": 70.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType": "SageMakerVariantInvocationsPerInstance"
},
"ScaleInCooldown": 600,
"ScaleOutCooldown": 300,
},
)
应用目标追踪策略到预定义指标。AWS 在"定义扩缩容策略"页面上的官方示例将每个实例的平均调用次数维持在 70。
确认告警是否存在
Application Auto Scaling 在策略背后创建了一对 CloudWatch 告警,查看它们是确认策略是否生效的最快方式。
aws cloudwatch describe-alarms \
--alarm-name-prefix TargetTracking-endpoint/tenant-scorers
确认告警是否存在。Application Auto Scaling 在策略背后创建了一对 CloudWatch 告警,查看它们是确认策略是否生效的最快方式。
目标追踪策略
数字 70 不是吞吐量指标,把它当作吞吐量来理解是这里最常见的错误。InvocationsPerInstance 是每个实例每分钟的调用次数。因此目标值 70 意味着大约每秒每个实例处理 1.2 个请求——这要么极其保守,要么极其激进,完全取决于你一次推理需要多长时间。应该用推导的方式:先确定一个实例在不影响 p95 延迟的情况下能承载多少并发请求,乘以 60,再除以平均推理耗时(秒)。如果一个实例在每次推理 2 秒的情况下能轻松处理 4 个并发请求,那就是每分钟约 120 次调用,目标值应该设在这个数字以下一些以留出余量。
在这个指标上做目标追踪对于稳定的请求-响应流量来说确实是正确的默认选择。对于生成类工作负载来说这不是什么好选择,原因见下一节。
为什么反应慢,以及该用什么替代
两层独立的延迟叠加在一起。首先,AWS 文档指出标准 CloudWatch 指标(包括 InvocationsPerInstance)每分钟才发出一次。其次,目标追踪通过 CloudWatch 告警工作,而告警需要连续几个数据点才会触发。再加上 SageMaker 扩容一个实例并拉起容器所需的时间,从流量进入到容量就绪之间的间隔是以分钟计而非秒级。
当每个请求耗时 50 毫秒且队列以与填充相同的速度消耗时,这个延迟是可以接受的。当每个请求占用实例 30 秒时这就不可接受了,因为突发流量不会排队——它直接导致饱和,而本应告诉你的那个指标是调用计数,当请求时间长的时候它不会上升。一个被十个慢速生成占满的终端节点和一个空闲的终端节点可能报告相近的调用计数。
AWS 为这个问题专门添加了预定义指标。SageMakerVariantConcurrentRequestsPerModelHighResolution 追踪并发请求数、计算排队在容器内的请求,以及——根据 AWS 文档——对于流式输出 token 的模型,它追踪每个请求直到最后一个 token 发出。它每 10 秒发出一次而非每 60 秒。对于推理组件,相应的指标是 SageMakerInferenceComponentConcurrentRequestsPerCopyHighResolution。如果你在托管任何生成类服务,从这里入手而非调用计数。
TargetTrackingScalingPolicyConfiguration={
"TargetValue": 5.0,
"PredefinedMetricSpecification": {
"PredefinedMetricType":
"SageMakerVariantConcurrentRequestsPerModelHighResolution"
},
}
AWS 指出这些高分辨率指标扩容速度比标准指标快得多,但缩容速度与标准指标相同。这种不对称是有意为之的,你不应该试图消除它。
对于任何 CPU 密集型而非并发密集型的工作负载来说,第三个选择是使用 /aws/sagemaker/Endpoints 命名空间下 CPUUtilization 的自定义指标,加上 EndpointName 和 VariantName 维度。注意取值范围:AWS 文档指出 CPUUtilization 是所有核心的累加值,所以一个四核实例的范围是 0–400%,四核实例上目标值 50 与你可能想要的含义完全不同。
冷却时间以及你需要的非对称性
ScaleOutCooldown 和 ScaleInCooldown 是可选的,但两个都应该设置。AWS 的工作示例用 300 秒扩容、600 秒缩容,这种非对称性是正确的直觉的一般化:扩容太慢会增加当前延迟,缩容太慢会持续浪费钱,后者是更便宜的错误。
在多模型终端节点上,这种非对称性比平时更重要。一个新实例启动时模型缓存是空的,所以它的第一批请求在响应前各自要支付一次完整的下载和加载代价。因此在负载下扩容反而会在改善情况之前短暂地使延迟变差,而缩容则会丢弃你花了成本构建的暖缓存。两侧都设置更长的冷却时间,以及选择一个比正常情况更高的 MinCapacity,是常见的应对方式。
最后,注意不要给一个目标附加多条策略。AWS 警告说有多条策略时,扩容和缩容都以最大容量为准,这意味着你作为安全网添加的策略可能会悄无声息地变成唯一实际起作用的策略。如果终端节点一天中大部分时间都空闲,那问题就不是该扩缩到多少——而是它到底应不应该是一个实时终端节点——参见《为什么 SageMaker 终端节点比预期更费钱》。
Deploying a Container to a SageMaker Real-Time Endpoint
Why a SageMaker Endpoint Costs More Than Expected
SageMaker Serverless Inference: Setup and Its Real Limits