LogoTensorFusion 文档
LogoTensorFusion 文档
首页

快速开始

TensorFusion 概览在 Kubernetes 安装在虚拟机/服务器安装(K3S)Helm 快速安装在宿主机/虚拟机安装TensorFusion 架构

应用操作

创建 AI 应用注解使用场景配置自动扩缩容迁移现有应用最佳实践

自定义AI基础设施

生产级部署指南QoS 级别与计价云厂商集成(BYOC)管理许可证

维护与优化

组件更新配置告警GPU 热迁移预加载模型优化 GPU 效率

故障排除

问题处理手册链路追踪/性能分析查询指标和日志

参考

对比

与 NVIDIA vGPU 对比与 MIG/MPS 对比与趋动科技对比与 NVIDIA Run:ai 对比与 HAMi 的对比

优化 GPU 效率

先量出资源池分配了多少、实际用了多少,再调整工作负载的资源配置、让负载排得更紧凑,并释放空闲节点

GPU 资源池的浪费主要有两种:工作负载申请的比实际用的多;已分配的资源分散在过多的节点上。本页先用 TensorFusion 已经采集的指标把这两种浪费量出来,再依次介绍四项对应的配置:工作负载自动伸缩、放置策略、节点合并和碎片整理。

前置条件

  • 已安装 TensorFusion,至少有一个处于 Running 的 GPUPool,并且工作负载已经运行了一段时间,能看出用量规律。建议至少一天。
  • 能访问 GreptimeDB,见查询指标和日志。
  • 已打开 hypervisor 的 vector sidecar。实际用量(tf_gpu_usage、tf_worker_usage)和工作负载自动伸缩都依赖它,见采集 hypervisor 指标和日志。
  • 有权限修改 TensorFusionCluster 和 SchedulingConfigTemplate。

本页涉及的资源池配置都写在 TensorFusionCluster 的 spec.gpuPools[].specTemplate 下面。controller 会用这份模板覆盖派生出的 GPUPool。

步骤 1:测量分配量和使用量

按节点对比三个数:总量、分配出去多少、实际用了多少。

最近一天各节点的分配比例:

SELECT node, pool,
       avg(allocated_tflops_percent) AS tflops_allocated_pct,
       avg(allocated_vram_percent)   AS vram_allocated_pct
FROM tf_node_metrics
WHERE greptime_timestamp >= now() - '1d'::INTERVAL
GROUP BY node, pool
ORDER BY tflops_allocated_pct;

最近一天每张 GPU 的使用比例:

SELECT node, uuid,
       avg(compute_percentage) AS compute_used_pct,
       max(memory_percentage)  AS vram_peak_pct
FROM tf_gpu_usage
WHERE greptime_timestamp >= now() - '1d'::INTERVAL
GROUP BY node, uuid
ORDER BY compute_used_pct;

每个工作负载的申请量和使用量。分别执行两条查询,按 workload 对照:

SELECT workload,
       avg(tflops_request)                  AS tflops_request,
       avg(vram_bytes_request) / 1073741824 AS vram_request_gib
FROM tf_worker_resources
WHERE greptime_timestamp >= now() - '1d'::INTERVAL
GROUP BY workload;

SELECT workload,
       avg(compute_tflops)             AS tflops_avg,
       max(compute_tflops)             AS tflops_peak,
       max(memory_bytes) / 1073741824  AS vram_peak_gib
FROM tf_worker_usage
WHERE greptime_timestamp >= now() - '1d'::INTERVAL
GROUP BY workload;

结果这样解读:

现象说明对应步骤
分配比例高,使用比例低工作负载申请的比需要的多步骤 2
节点上每张 GPU 都有一点负载,大的请求哪里都放不下负载铺得太散步骤 3
有的节点完全没有分配这些节点可以释放步骤 4
很多节点都只分配了一点容量在节点之间碎片化了步骤 5

不想写 SQL 的话,kubectl get gpunode 和 kubectl get gpu 也能看到 TFLOPS 和显存的总量与可用量。内置告警 IdleGPU 和 EmptyGPU 会持续检查同样的情况,见配置告警。

步骤 2:调整工作负载的请求值

调度器按工作负载的请求值预留资源。请求值高于实际用量,多出来的部分就白白占着。可以根据步骤 1 的数字手动调低,也可以交给自动伸缩,让请求值跟着实际用量走。在 Pod 模板上加两条注解即可开启:

metadata:
  annotations:
    tensor-fusion.ai/autoscale: "true"
    tensor-fusion.ai/autoscale-target: all   # all、compute 或 vram

之后 controller 会根据工作负载的历史用量算出推荐值,并应用到各个 worker。这需要 controller 带 -enable-auto-scale 启动参数,chart 默认已经加上。查看推荐值:

kubectl get tensorfusionworkload <workload> -n <namespace> -o jsonpath='{.status.recommendation}'

百分位、上下界、定时伸缩和资源池级规则等配置,见配置自动扩缩容。

步骤 3:选择放置策略

放置策略决定新的工作负载落到哪张 GPU 上,在资源池引用的 SchedulingConfigTemplate 的 spec.placement.mode 里设置。

策略行为适用情况
NodeCompactGPULowLoad(默认)节点一个一个填满,节点内部把负载分散到各张 GPU想少用节点,又不想让单张 GPU 太挤
CompactFirst在放得下的 GPU 里选剩余容量最少的成本优先,并且需要留出整张空闲 GPU 给大请求
LowLoadFirst选剩余容量最多的 GPU性能隔离比节点数量更重要

修改 chart 创建的模板:

kubectl patch schedulingconfigtemplate tf-scheduling-config --type=merge \
  -p '{"spec":{"placement":{"mode":"CompactFirst"}}}'

新策略只对之后调度的工作负载生效。运行中的工作负载留在原地,直到重启或被碎片整理挪走。

步骤 4:释放空闲节点

节点合并按固定周期检查资源池,把没有运行任何 TensorFusion 工作负载的 GPU 节点释放掉,前提是释放之后资源池的容量仍然够用。

capacityConfig:
  minResources:
    tflops: "20"
    vram: 10Gi
  warmResources:
    tflops: "10"
    vram: 5Gi
nodeManagerConfig:
  nodeCompaction:
    period: 30m
配置含义
nodeCompaction.period检查周期。chart 设置的是 30m
capacityConfig.warmResources释放节点之后,资源池里必须保留的空闲容量
capacityConfig.minResources释放节点之后,资源池里必须保留的总容量

同时满足下面几个条件,节点才会被释放:节点上没有 TensorFusion worker;对应的 GPUNode 处于 Running 且创建超过 5 分钟;没有 tensor-fusion.ai/do-not-disrupt: "true" 标签;释放后不违反 warmResources 和 minResources。

“释放”具体做什么,取决于资源池的 provisioningMode:

模式节点合并做的事
AutoSelect给 Kubernetes Node 打上 tensor-fusion.ai/should-delete=true 标签。TensorFusion 不会删除节点,要由节点自动伸缩组件来删,例如 Karpenter 的 consolidation
Provisioned、Karpenter删除 TensorFusion 为该节点创建的 GPUNodeClaim,节点随之销毁。不是 TensorFusion 创建的节点会被跳过

不想等下一个周期,可以给资源池打一条值为当前时间的注解,立即触发一次检查。时间戳超过 3 秒 controller 就不认:

kubectl annotate gpupool <pool> --overwrite \
  tensor-fusion.ai/manual-compaction="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

AutoSelect 模式的资源池可以这样查看哪些节点被标记了:

kubectl get nodes -l tensor-fusion.ai/should-delete=true

步骤 5:整理低利用率节点

节点合并只能释放已经空了的节点,把节点腾空要靠碎片整理:它按 cron 定时,把在用 GPU 较少的节点上的 TensorFusion worker 驱逐掉,让调度器把它们放到更满的节点上,腾空的节点再交给节点合并释放。碎片整理默认关闭。

碎片整理会驱逐 Pod。被驱逐的工作负载在别的节点上重启,并重新加载模型,这不是热迁移。请安排在业务低峰期执行。

  1. 给每个允许被挪动的工作负载加上 PodDisruptionBudget。节点上只要有一个 TensorFusion worker Pod 没有被覆盖,这个节点就会被跳过。

  2. 在资源池上开启碎片整理。timezone 必填:

    nodeManagerConfig:
      nodeCompaction:
        period: 30m
        defrag:
          enabled: true
          schedule: "0 3 * * *"
          timezone: "UTC"
          maxDuration: 2h
          utilizationThresholdPercent: 40
    字段默认值含义
    enabledfalse是否开启碎片整理
    schedule0 3 * * *5 段 cron 表达式,不要加 TZ= 前缀
    timezone无,必填计算 schedule 用的 IANA 时区,例如 UTC、Asia/Shanghai
    maxDuration2h单次执行的最长时间。创建时间短于这个值的 worker 也不会被驱逐
    utilizationThresholdPercent40节点上至少承载一个 worker 的 GPU 占比不超过这个值时,节点成为候选。完全空闲的节点留给节点合并处理
  3. 到了设定时间之后,在资源池的事件里查看执行情况:

    kubectl describe gpupool <pool>

    DefragStarted、DefragPodEvicted、DefragFinished 表示一次正常的执行;DefragSkipMissingPDB 会指出哪个 Pod 没有 PodDisruptionBudget。

碎片整理的策略比较保守:一次只驱逐一个 Pod,并且先模拟调度,确认节点上所有 worker 都能放进利用率不低于当前节点的其他节点才动手。被设为不可调度的节点、带 tensor-fusion.ai/do-not-disrupt: "true" 标签的节点,以及运行着不经 TensorFusion 使用 GPU 的 Pod 的节点,都会被跳过。

验证

至少等一个节点合并周期;开启了碎片整理的话,再等它执行一次。然后重新执行步骤 1 的查询,对比前后变化:

  • 留下来的节点分配比例更高了。
  • 节点数量减少了:kubectl get gpunode。
  • WorkerTFlopsThrottled 告警没有开始触发。如果触发了,说明这些工作负载的请求值或限制值被调得太低。

限制

  • 节点合并和碎片整理都不会挪动运行中的进程,靠的是 Pod 在别处重启。见 GPU 热迁移。
  • AutoSelect 模式下 TensorFusion 只给节点打标签。没有节点自动伸缩组件来删除节点的话,什么都不会释放。
  • SchedulingConfigTemplate 里有一个 reBalancer 配置块,controller 目前不处理它。
  • chart 没有放置策略和碎片整理对应的 value。每次 helm upgrade 之后请确认这两项配置还在。

下一步

  • 配置自动扩缩容:自动伸缩的完整配置。
  • 配置告警:GPU 闲置、资源池耗尽时收到通知。
  • 查询指标和日志:更多可以分析的表。

预加载模型

TensorFusion 在缩短模型冷启动上做了什么、没做什么,以及怎么用 Kubernetes 标准卷缓存模型权重

问题处理手册

按现象排查 TensorFusion 的常见问题,从 GPU 没被发现、Pod 一直 Pending 到限额不生效

目录

前置条件
步骤 1:测量分配量和使用量
步骤 2:调整工作负载的请求值
步骤 3:选择放置策略
步骤 4:释放空闲节点
步骤 5:整理低利用率节点
验证
限制
下一步