Modal GPU 任务排队排查与调度

说明如何区分 Modal 的容器等待与首次初始化,并据 GPU 回退、热容器、并发和空闲窗口调整任务调度,同时核对任务提交与完成状态,避免把单纯延长等待误判为任务失败。

Modal GPU 任务排队时,先分清是在等可用容器、等新容器完成初始化,还是并发设置让输入等待;确认后再改 GPU 回退顺序、每容器卡数和热容器参数。对算力租赁任务来说,首次加载与空闲保留也必须一起核对,否则单纯加卡或保温可能只改善等待,却增加持续资源占用。

排查前要准备的基线

先记录当前的 gpu 请求,以及 max_inputs、target_inputs、max_containers、min_containers、buffer_containers 和 scaledown_window。再选一个可重复的短输入,为任务设置唯一标识,并记录函数入口与最终返回。这样才能区分尚未开始、正在初始化、已经执行但结果尚未取回这几种情况。

冷启动还是执行排队

按 Modal 的冷启动性能文档,没有 ready container 时,Modal 会启动新容器,这就是 cold start。相关延迟来自等待容器变为 warm,以及新容器首次调用前的 initialization。即使进程已经启动,全局代码和所有 @modal.enter 方法也必须执行完毕,容器才会接收输入。

排查时可把首次调用和后续调用分开观察:如果后续调用正常,而首个任务明显更慢,应先检查初始化路径,而不是立即增加 GPU 数量。

算力租赁中的 GPU 请求怎么改

Modal 的 GPU 加速指南 列出的 gpu 值包括 T4、L4、A10、L40S、A100、A100-40GB、A100-80GB、RTX-PRO-6000、H100/H100!、H200、B200/B200+ 和 B300。每容器请求超过 2 张 GPU 通常会带来更长等待,而且这些 GPU 始终位于同一台物理机;多数类型单容器最多支持 8 张,A10 最多支持 4 张。B300 还要求 CUDA 13.1 或更高版本。

gpu 可以接收有顺序的回退列表,Modal 会先尝试首项,再使用后续类型:

@app.function(gpu=["H100", "A100-40GB:2"])

如果首选 GPU 不适合当前负载,可以增加回退项;如果任务无法跨物理机分摊,也没有必要仅靠增加单容器卡数解决问题。

调整 Modal 的扩缩容参数

依据 Modal 的扩缩容文档,每个 Function 拥有独立的自动扩缩容容器池,默认在没有输入时缩到零。max_containers 是容器数上限,min_containers 是非活跃期仍保持 warm 的最低数量,buffer_containers 是活跃期保留的额外缓冲,scaledown_window 则决定容器最多空闲多久后缩容。

已部署的 Function 可以通过下面的调用调整上下限,无需重新部署;但下一次部署时,这些设置会恢复为 Function decorator 中的配置:

f.update_autoscaler(min_containers=2, max_containers=10)

间歇性请求应先核对 min_containers,突发流量再检查 buffer_containers,而 max_containers 应结合实际并发上限设置,避免把等待问题转化为持续资源占用。

短任务的并发设置

Modal 的输入并发文档 说明,每个容器默认一次处理一个输入。启用 @modal.concurrent 并设置 max_inputs 后,需求超过该值时 Modal 会增加容器,而额外输入可能在这些容器冷启动期间继续排队。target_inputs 是自动扩容器瞄准的并发量,活跃容器最多可以突发到 max_inputs。

@modal.concurrent(max_inputs=100)

上面的数值是文档示例,不应脱离模型内存条件照搬。Modal 建议根据期望延迟设置 target_inputs,根据 GPU 内存等资源约束设置 max_inputs,以避免 OOM。同步 Function 的并发输入运行在不同线程中,因此实现必须线程安全;这种模式也适合包含 vLLM continuous batching 的 GPU 容器。

验证提交与任务完成

Modal 的任务处理文档 给出的基本路径是:先部署 Function,再使用 Function.spawn() 提交任务,最后通过 FunctionCall.get() 轮询并取得结果。.spawn() 的结果在完成后最多可获取 7 天。

该页面没有定义独立的队列深度或启动状态接口,因此不要把 FunctionCall.get() 当成查询等待位置的工具。短任务验收可以先记录提交时间,再检查函数入口日志和最终返回;如果一直没有结果,再回到 GPU 数量、并发上限、热容器数量和回退顺序逐项核对。

调度成本如何核算

Modal 的 定价页 按秒计量 CPU、内存和 GPU 时间;计费覆盖应用加载、输入处理,以及最后一次输入后默认 60 秒的空闲保留期。容器缩到零后不再收费;CPU 和内存按请求量与实际使用量中的较高值计算,也不要求每个实例满足最低使用时长。

可先用占位符整理自己的账单数据:

GPU_SECONDS = Σ(LOAD_SECONDS + INPUT_SECONDS + KEEP_ALIVE_SECONDS)
CPU_CORE_SECONDS = Σ(MAX(REQUESTED_CPU_CORES, ACTUAL_CPU_CORES) × SECONDS)
MEMORY_MIB_SECONDS = Σ(MAX(REQUESTED_MEMORY_MIB, ACTUAL_MEMORY_MIB) × SECONDS)

RESOURCE_CHARGE = GPU_SECONDS × GPU_RATE
                 + CPU_CORE_SECONDS × CPU_RATE
                 + MEMORY_MIB_SECONDS × MEMORY_RATE

从自己的报价或账单填入费率、加载时间、实际处理时间和空闲保留时间,再单独核对其他适用项目。不要为了减少排队直接提高 min_containers 或 buffer_containers,应先确认新增等待时间是否值得持续占用资源。

本文仅按正文所链接的 Modal 官方文档整理,未运行或测量,使用前请对照当前版本复核。

资料来源