配置自动扩缩容
让 TensorFusion 按历史用量、定时规则或你自己的伸缩服务,调整运行中工作负载的 TFLOPS 和显存 request、limit
TensorFusion 的自动扩缩容是垂直方向的:在 Pod 不重启的情况下,调整每个 vGPU 的 TFLOPS 和显存 request、limit。它不改副本数,副本数请用 HPA 或 KEDA。
最快的开启方式是加一个注解。需要调整分位数、配置定时规则或接入外部伸缩服务时,用 WorkloadProfile。
前置条件
- 工作负载已经运行在 TensorFusion 上。参考创建 AI 应用。
- controller 启动参数带
-enable-auto-scale,并且能访问指标数据库。默认的 Helm 安装两者都已具备。 - 工作负载的算力用 TFLOPS(
tflops-request、tflops-limit)表示,不要用百分比。自动扩缩容的结果是以 TFLOPS 和显存写回的。
第 1 步:用注解开启
在 Pod 模板上资源注解的旁边加上:
metadata:
annotations:
tensor-fusion.ai/autoscale: "true"
# compute | vram | all,不写时为 all
tensor-fusion.ai/autoscale-target: "all"autoscale-target | 调整什么 |
|---|---|
compute | TFLOPS 的 request 和 limit |
vram | 显存的 request 和 limit |
all | 两者都调 |
只写这两个注解时,TensorFusion 使用第 2 步表格里的默认分位数配置。
第 2 步:用 WorkloadProfile 细调
把详细配置写在 WorkloadProfile 的 spec.autoScalingConfig 里,再在 Pod 上用 tensor-fusion.ai/workload-profile 引用它。
apiVersion: tensor-fusion.ai/v1
kind: WorkloadProfile
metadata:
name: autoscale-inference
spec:
autoScalingConfig:
autoSetResources:
enable: true
targetResource: all
historyDataPeriod: 6h
initialDelayPeriod: 30m
marginFraction: "0.2"autoSetResources.enable: true 是整个自动扩缩容的总开关。没有它,下文的定时规则和外部伸缩服务都不会生效。
enable 为 true 但 targetResource 为空时,TensorFusion 只把推荐值写到工作负载的 status 里,不做任何修改。可以用这种方式先观察自动扩缩容会怎么调。注解 tensor-fusion.ai/autoscale: "true" 总会带上目标资源,所以用注解开启时一定会实际修改。
基于用量的配置
这些字段在 YAML 里都是字符串,数字要加引号。
| 字段 | 默认值 | 含义 |
|---|---|---|
enable | false | 为这个工作负载开启自动扩缩容。 |
targetResource | 空 | compute、vram 或 all。为空表示只推荐不修改。 |
targetComputePercentile | 0.95 | 作为算力目标值的用量分位数。 |
lowerBoundComputePercentile | 0.5 | 作为算力下界的用量分位数。 |
upperBoundComputePercentile | 0.99 | 作为算力上界的用量分位数。 |
targetVRAMPercentile | 0.98 | 作为显存目标值的用量分位数。 |
lowerBoundVRAMPercentile | 0.5 | 作为显存下界的用量分位数。 |
upperBoundVRAMPercentile | 0.99 | 作为显存上界的用量分位数。 |
marginFraction | 0.15 | 在每个分位数之上追加的安全余量。 |
updateThreshold | 0.1 | 新 request 与当前值的差超过这个比例才会修改。应小于 marginFraction。 |
historyDataPeriod | 2h | 回看多长时间的用量,最长 30 天。 |
initialDelayPeriod | 30m | 工作负载创建后等待多久才开始调整。 |
interval | 全局间隔 | 多久评估一次。全局值是 Helm values 里的 dynamicConfig.autoScalingInterval,未设置时为 30s。 |
minComputeResourcesRatio | 0.1 | 算力 request 的下限,相对原始 request 的比例。 |
maxComputeResourcesRatio | 10.0 | 算力 request 和 limit 的上限,相对原始值的比例。 |
minVRAMResourcesRatio | 0.2 | 显存 request 和 limit 的下限,相对原始值的比例。 |
maxVRAMResourcesRatio | 5.0 | 显存 request 和 limit 的上限,相对原始值的比例。 |
推荐值按下面的规则从这些数字算出来:
- limit 取上界。
- request 取决于 QoS:
low和medium取下界,high取目标值,critical取上界。 - 结果被限制在上面的最小、最大比例之内,并且不低于 1 TFLOPS 或 1Gi。
- 算力 limit 不会低于原始 limit,避免工作负载空闲一段时间后流量回来时被限流。
- 调大时不会超过工作负载当前所用 GPU 上的空闲量。
定时扩缩容
定时规则在一个时间窗口内使用固定的资源。不在任何窗口内时,工作负载恢复到创建时的资源。
spec:
autoScalingConfig:
autoSetResources:
enable: true
targetResource: all
cronScalingRules:
- name: business-hours
enable: true
start: "0 9 * * 1-5"
end: "0 19 * * 1-5"
desiredResources:
requests:
tflops: "40"
vram: 8Gi
limits:
tflops: "80"
vram: 10Gistart和end是标准的五段 cron 表达式(分、时、日、月、周),两者不能相同,按 controller 所在的时区计算。- 缺少
name、start、end,或enable: false的规则会被跳过。 - 规则生效期间,基于用量的调整不会把 request 降到规则值以下。
接入外部伸缩服务
想在自己的服务里做决策,可以让 TensorFusion 调用一个 HTTP 接口:
spec:
autoScalingConfig:
autoSetResources:
enable: true
targetResource: all
externalScaler:
enable: true
url: http://my-scaler.default.svc:8080/recommend
apiKeySecretRef:
name: my-scaler-key
namespace: default每次评估时,TensorFusion 发送一个带 JSON body 的 POST 请求,期望收到 HTTP 200 和 JSON 响应。配置了 apiKeySecretRef 时,TensorFusion 从 Secret 的 apiKey、token 或 key 字段读取密钥,放在 Authorization: Bearer <key> 请求头里。
请求体:
{
"workloadName": "pytorch-vgpu",
"namespace": "default",
"currentResources": {
"requests": { "tflops": "10", "vram": "4Gi" },
"limits": { "tflops": "20", "vram": "4Gi" }
}
}响应体:
{
"needScaleUp": true,
"needScaleDown": false,
"reason": "QueueTooLong",
"recommendedResources": {
"requests": { "tflops": "20", "vram": "4Gi" },
"limits": { "tflops": "40", "vram": "4Gi" }
}
}needScaleUp 和 needScaleDown 都为 false 时不做修改。reason 不为空时会记录到工作负载的 status 里。externalScaler.initialDelayPeriod 默认为 30m。
一条规则套用到多个工作负载
池管理员可以按标签选择器给一批 Pod 统一加上自动扩缩容配置,不用逐个改工作负载。在池所用的 SchedulingConfigTemplate 里添加 verticalScalingRules:
kubectl get gpupool <pool-name> -o jsonpath='{.spec.schedulingConfigTemplate}{"\n"}'
kubectl edit schedulingconfigtemplate <template-name>spec:
verticalScalingRules:
- name: autoscale-inference
selector:
matchLabels:
workload-type: inference
autoScaling:
autoSetResources:
enable: true
targetResource: allPod 创建时,webhook 把第一条选择器匹配 Pod 标签的规则合并到工作负载的配置里。
第 3 步:查看调整结果
每个工作负载都有一个与其 Deployment、StatefulSet 或 Job 同名的 TensorFusionWorkload 对象,它的 status 反映当前状态:
kubectl get tensorfusionworkload <workload-name> -o yaml
kubectl get events --field-selector involvedObject.kind=TensorFusionWorkloadstatus:
conditions:
- type: ResourceUpdate
status: "True"
reason: Updated
message: "Compute scaled: request 10 -> 6, limit 20 -> 20"
# 最近一次推荐值
recommendation:
requests:
tflops: "6"
vram: 3Gi
limits:
tflops: "20"
vram: 4Gi
# 已应用推荐值的 Pod 数
appliedRecommendedReplicas: 3
# 只在定时规则生效期间出现
activeCronScalingRule:
name: business-hours| Condition | Reason | 含义 |
|---|---|---|
ResourceUpdate | LowConfidence | 工作负载创建时间还不到 initialDelayPeriod,暂不调整。 |
ResourceUpdate | InsideUpdateThreshold | 变化量小于 updateThreshold,不调整。 |
ResourceUpdate | Updated | 资源已调整,message 里有调整前后的值。 |
ResourceUpdate | NoScalingNeeded | 外部伸缩服务返回不需要调整。 |
RecommendationProvided | RuleActive、RuleInactive | 定时规则开始或结束。 |
每次调整还会在 TensorFusionWorkload 上产生一条 ResourceScaledUp 或 ResourceScaledDown 事件。
推荐值通过两条路径到达 Pod。运行中的 Pod,其 tflops-* 和 vram-* 注解被原地更新,Pod 不会重启。之后新建的 Pod 直接使用推荐值启动。
限制
- 不调整副本数。
- 带
tensor-fusion.ai/dedicated-gpu: "true"的 Pod 会被跳过,因为它们已经独占整卡。 - 工作负载创建后的第一个
initialDelayPeriod内不会有任何动作,定时规则和外部伸缩服务也同样被推迟。
TensorFusion 文档