max_num_seqs 参数详解 一、参数定义
max_num_seqs
是 vLLM 和 vLLM-Ascend 中一个关键的调度配置参数,用于限制 单个调度步骤中同时处理的最大序列(请求)数量 。
默认值 默认值 : 128 位置 :
vllm/vllm/config/scheduler.py
中的
SchedulerConfig.DEFAULT_MAX_NUM_SEQS
DEFAULT_MAX_NUM_SEQS: ClassVar[int] = 128
二、核心作用 1. 调度器层面的限制 在调度器(Scheduler)中,
max_num_seqs
被转换为
max_num_running_reqs
,用于限制 同时处于运行状态(RUNNING)的请求数量 。
代码位置 :
vllm/vllm/v1/core/sched/scheduler.py
# 第97行
self.max_num_running_reqs = self.scheduler_config.max_num_seqs
调度逻辑 :
# 第428-429行:当运行中的请求数达到上限时,停止从等待队列中调度新请求
if len(self.running) == self.max_num_running_reqs:
break
这意味着: 如果当前有 128 个请求正在运行(
max_num_seqs=128
),新的请求将停留在等待队列(WAITING)中 只有当某个运行中的请求完成或被抢占后,等待队列中的请求才能被调度 2. 内存分配和缓冲区大小
max_num_seqs
直接影响 Worker 中各种缓冲区的分配大小。
2.1 RequestState 缓冲区 代码位置 :
vllm/vllm/v1/worker/gpu/states.py
RequestState
类使用
max_num_reqs
(即
max_num_seqs
)来分配所有请求相关的状态缓冲区:
class RequestState:
def __init__(self, max_num_reqs: int, ...):
# 为每个请求分配固定大小的缓冲区
self.prompt_len = np.zeros(self.max_num_reqs, dtype=np.int32)
self.prefill_token_ids = UvaBuffer(
self.max_num_reqs, self.max_model_len, dtype=torch.int32
)
self.prefill_len = self._make_buffer(self.max_num_reqs, dtype=torch.int32)
self.num_computed_tokens = torch.zeros(
self.max_num_reqs, dtype=torch.int32, device=device
)
# ... 更多缓冲区
内存影响 :
prefill_token_ids
: 大小为
max_num_reqs × max_model_len × 4字节
(int32) 例如:128 × 32768 × 4 = 16MB(仅这一个缓冲区) 所有请求状态缓冲区的总大小与
max_num_seqs
成正比 2.2 InputBuffers 缓冲区 代码位置 :
vllm/vllm/v1/worker/gpu/model_runner.py
self.input_buffers = InputBuffers(
max_num_reqs=self.max_num_reqs, # 使用 max_num_seqs
max_num_tokens=self.max_num_tokens,
...
)
InputBuffers
用于存储每个推理步骤的输入数据,其大小也受
max_num_seqs
影响。
2.3 BlockTables 缓冲区 代码位置 :
vllm/vllm/v1/worker/gpu/model_runner.py
self.block_tables = BlockTables(
block_sizes=block_sizes,
max_num_reqs=self.max_num_reqs, # 使用 max_num_seqs
max_num_batched_tokens=self.max_num_tokens,
...
)
BlockTables 用于管理 KV Cache 的块表,其大小也与
max_num_seqs
相关。
3. 数据并行(DP)场景下的特殊含义 在 vLLM-Ascend 的文档中明确指出:
--max-num-seqs
表示 每个 DP group 允许处理的最大请求数 。
如果发送到服务的请求数超过此限制,多余的请求将保持在等待状态,不会被调度。
重要公式 :
总并发能力 = max_num_seqs × data_parallel_size
示例 : 如果
max_num_seqs=16
,
data_parallel_size=2
那么总共有 16 × 2 = 32 个请求可以同时运行 如果实际并发请求数为 40,那么有 8 个请求会处于等待状态 性能测试建议 : 在测试性能时,一般建议
max_num_seqs × data_parallel_size >= 实际总并发数
,否则等待时间也会被计入 TTFT(Time To First Token)和 TPOT(Time Per Output Token)等指标中。
4. 与 max_num_batched_tokens 的关系
max_num_seqs
和
max_num_batched_tokens
共同决定了批处理的能力: 验证逻辑 (
vllm/vllm/config/scheduler.py
):
# 第264-269行:max_num_batched_tokens 必须 >= max_num_seqs
if self.max_num_batched_tokens < self.max_num_seqs:
raise ValueError(
f"max_num_batched_tokens ({self.max_num_batched_tokens}) must "
"be greater than or equal to max_num_seqs "
f"({self.max_num_seqs})."
)
关系说明 :
max_num_batched_tokens
: 限制单次推理步骤中处理的 总 token 数
max_num_seqs
: 限制单次推理步骤中处理的 总请求数 理论上,如果每个请求只有 1 个 token,最多可以处理
max_num_batched_tokens
个请求 但实际上,由于
max_num_seqs
的限制,最多只能处理
max_num_seqs
个请求 警告逻辑 (第271-277行):
if self.max_num_batched_tokens > self.max_num_seqs * max_model_len:
logger.warning(
"max_num_batched_tokens (%d) exceeds max_num_seqs "
"* max_model_len (%d). This may lead to unexpected behavior.",
...
)
三、影响范围 1. 内存占用 直接影响 : 所有请求状态缓冲区的大小 InputBuffers 的大小 BlockTables 的大小 采样参数缓冲区的大小 内存计算公式 (简化):
额外内存 ≈ max_num_seqs × (
max_model_len × 4 + # prefill_token_ids
各种状态缓冲区大小
)
2. 调度性能 正面影响 : 吞吐量 : 较大的
max_num_seqs
允许更多请求并发处理,可能提高吞吐量 GPU 利用率 : 更多请求可以更好地利用 GPU 的并行计算能力 负面影响 : 延迟 : 如果
max_num_seqs
太小,请求会在等待队列中停留更长时间 内存压力 : 更大的
max_num_seqs
需要更多 GPU 内存 3. 并发处理能力 限制因素 : 如果实际并发请求数 >
max_num_seqs × data_parallel_size
,多余的请求会排队等待 等待时间会被计入性能指标(TTFT、TPOT),影响用户体验 4. 批处理效率 批处理大小 : 每次推理步骤最多处理
max_num_seqs
个请求 如果请求数 <
max_num_seqs
,批处理可能不够满,GPU 利用率可能下降 如果请求数 >
max_num_seqs
,需要多步处理,可能增加延迟 四、使用建议 1. 根据硬件资源调整 GPU 内存充足时 : 可以设置较大的
max_num_seqs
(如 256、512) 提高并发处理能力和吞吐量 GPU 内存受限时 : 需要减小
max_num_seqs
(如 64、32) 避免 OOM(Out of Memory)错误 2. 根据工作负载调整 高并发场景 : 确保
max_num_seqs × data_parallel_size >= 预期并发数
避免请求长时间等待 低延迟优先场景 : 可以适当减小
max_num_seqs
减少批处理大小,降低单步处理时间 高吞吐量优先场景 : 增大
max_num_seqs
提高批处理效率 3. 与 max_num_batched_tokens 的平衡 经验法则 :
max_num_batched_tokens
应该 >=
max_num_seqs
对于短序列请求,可以设置
max_num_batched_tokens
远大于
max_num_seqs
对于长序列请求,需要确保
max_num_batched_tokens
足够大以处理长序列 4. 数据并行场景 重要公式 :
总并发能力 = max_num_seqs × data_parallel_size
建议 : 在设置
max_num_seqs
时,考虑
data_parallel_size
确保总并发能力满足实际需求 五、代码示例 1. 在 vLLM 中设置
from vllm import LLM
llm = LLM(
model="your-model",
max_num_seqs=128, # 设置最大序列数
max_num_batched_tokens=2048, # 必须 >= max_num_seqs
)
2. 在 vLLM-Ascend 中设置
vllm serve Qwen/Qwen3-VL-235B-A22B-Instruct \
--max-num-seqs 16 \
--data-parallel-size 2 \
--max-num-batched-tokens 4096 \
...
3. 验证配置
# 在 SchedulerConfig 中会自动验证
# 如果 max_num_batched_tokens < max_num_seqs,会抛出 ValueError
六、常见问题 Q1: max_num_seqs 设置太小会怎样?
A : 请求会在等待队列中停留更长时间 吞吐量下降 延迟增加(等待时间计入 TTFT/TPOT) Q2: max_num_seqs 设置太大会怎样?
A : GPU 内存占用增加 可能导致 OOM 批处理效率可能下降(如果实际请求数远小于 max_num_seqs) Q3: 如何确定合适的 max_num_seqs?
A : 根据 GPU 内存容量估算 根据实际并发需求计算:
max_num_seqs × data_parallel_size >= 并发数
通过性能测试找到最佳平衡点 Q4: max_num_seqs 和 max_num_batched_tokens 的区别?
A :
max_num_seqs
: 限制 请求数量
max_num_batched_tokens
: 限制 token 数量 两者共同决定批处理能力 七、总结
max_num_seqs
是 vLLM 中一个关键的调度和资源管理参数,它: 限制并发 : 控制同时处理的请求数量 分配内存 : 决定各种缓冲区的分配大小 影响性能 : 直接影响吞吐量、延迟和 GPU 利用率 与 DP 相关 : 在数据并行场景下,总并发能力 =
max_num_seqs × data_parallel_size
合理设置
max_num_seqs
需要在 内存占用 、 并发能力 和 性能指标 之间找到平衡点。
