Modal 并行推理任务调度教程
使用 Modal 的 Function.map() 并行处理推理输入,并通过 GPU、容器伸缩、输入并发与动态批处理参数组织任务,同时核对结果顺序、异常传播和空闲计费。
在 Modal 上调度并行推理任务,核心是用 Function.map() 并行处理输入、按原顺序取回结果,并以 max_containers、min_containers、buffer_containers 和 scaledown_window 控制容器池,详见 Modal 的容器扩缩说明。GPU 选择、单容器并发和容器上限应分别设置:前者确定硬件,后两者决定一批输入如何进入执行池。大模型部署还必须同时核对冷启动、空闲保留和计费口径。
准备 Modal 上的大模型部署资源
使用 GPU 前,账户中要有有效付款方式;Modal 的 GPU 加速说明列出的 gpu 值包括 T4、L4、A10、L40S、A100、A100-40GB、A100-80GB、RTX-PRO-6000、H100/H100!、H200、B200/B200+ 和 B300。该说明建议推理先从具有 48 GB GPU RAM 的 L40S 开始,但能否装入模型仍要结合权重和激活所需显存判断。
gpu 可以写成有序回退列表,Modal 会先尝试首选类型;用 :n 指定单容器 GPU 数量。大多数类型最多支持 8 张,A10 最多支持 4 张。请求超过 2 张通常等待更久,同一容器的 GPU 始终位于同一台物理机上。
@app.function(gpu=["H100", "A100-40GB:2"])
该配置先请求 H100,无法分配时再回退到两张 A100-40GB。B300 要求 CUDA 13.1 或更高版本,容器镜像和依赖也必须兼容。
用容器池参数安排并行调度
每个 Modal Function 都有独立的自动扩缩容器池。没有输入时默认缩到零;新输入没有可用容量时增加容器,资源空闲后再缩容。
max_containers:Function 的容器数上限。min_containers:非活动时仍保留的最小热容器数;设为正数后形成不再缩到零的下限。buffer_containers:Function 活动期间预留的额外容器数,用于缓冲新增输入。scaledown_window:单个容器缩容前允许保持空闲的最长时间,单位为秒。
对已部署的 Function,可以直接更新自动扩缩参数:
f.update_autoscaler(min_containers=2, max_containers=10)
这次更新无需重新部署;下次部署 App 时,参数会恢复为函数装饰器中的配置。
选择单容器并发或动态批处理
默认每个容器一次处理一个输入。Modal 的输入并发说明允许通过以下装饰器启用并发输入:
@modal.concurrent(max_inputs=100)
target_inputs 是自动扩缩器希望达到的并发量;现有容器可以超过该目标,但最多达到 max_inputs。Modal 建议根据期望延迟设置 target_inputs,根据 GPU 内存等资源约束设置 max_inputs,以避免 GPU OOM。需求超过 max_inputs 后,Modal 会增加容器,但新增输入可能在这些容器冷启动期间排队。
同步 Function 的并发输入分别运行在线程上,因此实现必须线程安全;async Function 使用同一线程中的 asyncio tasks。共享可变状态不能默认视为安全。
如果输入需要先聚合再执行,可采用 Modal 的动态批处理说明中的配置:
@modal.batched(max_batch_size=2, wait_ms=1000)
max_batch_size 是批次数量阈值,wait_ms 是等待阈值;执行会等到两者中先满足的条件出现。先明确要解决的是单容器同时处理,还是等待请求成批,再决定配置方式。
检查结果和异常
Function.map() 返回的可迭代结果与输入顺序一致。验证时,应为输入附带可区分的标识,并按返回顺序核对每项结果,而不能只看容器是否启动。
默认情况下,任一调用抛出异常都会向外传播。设置 return_exceptions=True 后,异常会作为结果收集,但仍需逐项区分正常返回值和异常对象。
冷启动和计费要一起核对
没有可用热容器时,Modal 必须启动新容器。Modal 的冷启动说明将相关延迟分为等待热容器和首次调用初始化两部分;全局代码及 enter 方法完成前,容器不会被视为可用,也不会接收输入。提前下载模型权重,并让可行的大型文件读取并发执行,可以减少启动阶段的工作。把工作移入 enter 只会把延迟移到预热期,并不会消除它。
Modal 的定价说明对 CPU、内存和 GPU 计算用量按秒计量,计费时间包括应用加载、输入处理,以及最后一次输入后默认 60 秒的空闲保留期;缩到零容器后不再收费。CPU 和内存按请求量与实际用量中的较高者计费。只核对资源费用时,可按自己的账单填入:
YOUR_VALUE = YOUR_GPU_FEE + YOUR_CPU_FEE + YOUR_MEMORY_FEE
延长 scaledown_window 可降低后续请求遇到冷启动的机会,但空闲期间占用的资源仍会计费。min_containers 和 buffer_containers 也会改变资源保留范围,应在部署前结合流量形态复核。
常见出错点
- 把
max_inputs直接设得很大,忽略模型权重和激活所需资源,结果可能触发 GPU OOM。 - 在同步 Function 中共享可变全局状态;并发输入分别在线程上运行时,这类实现可能破坏线程安全。
- 把单容器多 GPU 当成跨物理机扩展;同一容器的 GPU 始终位于同一台机器,请求超过 2 张还可能增加等待。
- 做 GPU 基准比较时仍使用
gpu="H100",实际可能自动升级到 H200。Modal 建议这类场景使用gpu="H100!"阻止升级。
上述步骤按正文链接的官方文档整理,未运行或测量示例,使用前应对照当前版本复核。