Serverless GPU 预留并发与预置容量配置

说明如何在 Modal 设置热容器与并发上限,在 RunPod 区分 Active workers 和 max workers,并按请求记录核查模型加载、排队与冷启动。

GPU服务器租用时,“预留并发”回答“同时最多处理多少工作”,“预置容量”回答“是否提前保留可接收请求的容器或 worker”。两者必须分开设置:扩缩容上限不能替代热容量,长期使用承诺也不能替代已经运行的 Serverless endpoint。

GPU服务器租用中的两类控制

先从自己的请求记录填写峰值并发、请求持续时间、流量形态和可接受的热容量成本;没有这些基线,就先验证再扩大。文档中的示例值、默认值和推荐比例都需要结合你的模型与流量理解,不能直接视为容量承诺。

预留并发:先确定处理上限

Modal:区分单容器与 Function 上限

根据 Modal 的输入并发文档,每个 container 默认一次处理一个 input;@modal.concurrent 与 max_inputs 用于启用输入并发,target_inputs 应按期望延迟设置,max_inputs 应按 GPU 内存等资源约束设置以避免 OOM。需求超过 max_inputs 时,Modal 会增加 containers,额外 inputs 可能在 cold start 期间排队;同步 Function 的并发 inputs 由不同线程执行,因此代码必须线程安全。

@modal.concurrent(max_inputs=100)

代码沿用官方示例。确定自己的数值时,应分别评估期望延迟与单容器资源上限,而不是直接复制示例。

RunPod:设置 max workers 与扩容条件

RunPod 的 Endpoint 设置文档中,Active workers 默认为 0,max workers 默认为 3;max workers 是并发 worker 上限,文档建议将其设为预期峰值并发以上约 20%。queue-delay scaling 会在请求等待超过阈值时增加 worker,默认阈值为 4 秒;面向 LLM 或频繁短请求的 request-count scaling 使用以下目标 worker 数公式。

Math.ceil((requestsInQueue + requestsInProgress) / scalerValue)

峰值、排队量和执行中请求数应来自自己的观测记录。文档中的 20% 是配置建议,不是所有模型都适用的固定答案。

预置容量:再确定保留多少资源

Modal:保留 warm containers

Modal 的 扩缩容文档说明,每个 Function 都有独立的 autoscaling container pool,无输入时默认缩到 0;min_containers 定义非活跃时保留的 warm containers 数量,buffer_containers 定义活跃时的额外缓冲,max_containers 是该 Function 的容器上限,scaledown_window 是缩容前容器可保持空闲的最大秒数。已部署 Function 可以通过 Function.update_autoscaler() 更新设置而无需重新部署,但下次部署会恢复 decorator 中的值。

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

这里的 2 和 10 是文档示例,不是默认配置。部署前应确认这些值已经写入最终生效的 decorator。

RunPod:区分 Active 与 Flex workers

根据 RunPod 的 worker 概览,Active workers 会持续保持 warm and ready,设置为 1+ 可消除 cold starts,但包括 idle 在内会持续计费;Flex workers 在闲置时会缩到 0,不产生闲置费用,但扩容时会出现 cold start。账户级 worker 上限还取决于余额,文档给出的默认起点是 5。

因此,Active workers 对应持续保留容量,Flex workers 对应按需启停;max workers 仍是独立的并发边界,不能代替 worker 类型选择。

AWS:采购层面的容量预留

如果需求是预留集群而非维持 endpoint worker,可查看 AWS 的 EC2 购买选项说明:Capacity Blocks 可用于预留 GPU 实例集群;Reserved Instances 对特定实例类型和 Region 作出 1 年或 3 年承诺;Savings Plans 则对以美元/小时计量的持续使用量作出 1 年或 3 年承诺。这些采购方式不等同于 Modal 或 RunPod 的热容器设置。

费用核对:不要只看执行时间

RunPod 的 Serverless 计费说明规定,计费从 worker 启动开始,到 worker 完全停止结束,并向上取整到下一秒;启动阶段包含容器初始化和模型加载,执行阶段与 idle-timeout 阶段也属于可计费 worker 时间。

可按下面的方法核对单次请求:

计费秒数 = ceil((停止时刻 - worker 启动时刻) / 1 秒)
请求费用 = 计费秒数 × YOUR_VALUE

将 YOUR_VALUE 替换为当前官方报价中与按秒计费对应的单价。Active workers 还要单独按持续保留时间核对,不能只按请求执行时间估算。AWS 长期方案则应把报价页中的承诺金额、期限、实例类型、Region 和其他列明项目逐项相加,本文不代填金额。

如何确认配置生效

配置后先核对最终部署使用的 decorator 值与临时 autoscaler 值,避免部署后恢复旧配置,再通过现有业务请求路径检查返回结果。若要核查冷启动,只有在请求记录确实提供请求到达、排队、模型加载完成、worker ready 和结束时间戳时,才能比较这些节点;本文所引官方页面没有列出通用日志字段名或导出命令,具体查询方式应以提供方当前文档为准,不能仅凭总延迟判断。

常见出错点

  • 把 max_containers 或 max workers 当成已经保留的热容量。
  • 把文档示例或推荐比例直接当作生产配置。
  • 启用输入并发后,仍让同步 Function 共享不具备线程安全性的状态。
  • 估算 RunPod 费用时漏掉启动、模型加载或 idle 阶段。
  • 只更新运行中的 autoscaler,却忘记确认下一次部署会采用的 decorator 值。

本文步骤依据正文所链接的官方文档整理,使用前请按当前版本复核。

资料来源