tritonserver
Triton Inference Server 的批处理槽(Batch Slot)机制,可以理解为是为有状态模型(Stateful Model)设计的一种“专属座位”或“状态容器”。
它的核心目的是:为每一个独立的序列(Sequence)在模型实例中分配一个固定的、专用的位置,确保该序列的所有推理请求都能被路由到同一个位置,从而正确地维护和更新模型内部的序列状态。
为了更好地理解,可以把一个模型实例想象成一个多座的办公室,而每个“批处理槽”就是其中一个固定的工位。
🗺️ 批处理槽的核心概念与工作原理
下面通过一个具体的例子来说明它是如何运作的。
假设你在 config.pbtxt 中做了如下配置:
max_batch_size: 2:这意味着每个模型实例有 2个批处理槽(槽0和槽1)。instance_group { count: 2 }:这意味着模型会启动 2个实例(实例0和实例1)。
那么,Triton 就可以同时处理 2个实例 × 2个槽 = 最多4个并发序列。
一个批处理槽的完整生命周期如下:
- 分配:当一个新序列的第一个请求(
sequence_start=True)到达时,序列调度器会寻找一个空闲的批处理槽。如果找到,就将这个序列与该槽位“绑定”。 - 占用:在该序列的整个生命周期内,这个槽位就像它的“私人包厢”。无论后续有多少个请求,都会被精准地导向同一个模型实例的同一个槽位。模型在处理时,可以根据槽位索引来维护独立的状态(例如,为槽0维护一套隐藏状态,为槽1维护另一套)。
- 释放:当序列的最后一个请求完成(
sequence_end=True)后,该序列结束。这个批处理槽被释放,变为空闲状态,等待分配给下一个新到来的序列。 - 超时与强制释放:如果一个序列在配置的
max_sequence_idle_microseconds时间内没有新的请求到达(即“发呆”超时),Triton 会强制终止该序列并释放其占用的槽位,以防止资源被死锁的客户端长期占用。
📊 批处理槽策略:Direct vs. Oldest
序列批处理器主要通过两种策略来管理这些槽位,理解它们能帮你更准确地配置模型。
| 策略 | 核心机制 | 槽位关系 | 适用场景 | 关键特点 |
|---|---|---|---|---|
| Direct (直接策略) | 为每个序列分配一个专用的、固定的批处理槽。 | 一对一绑定。一个槽在整个序列生命周期内只服务一个序列。 | 模型必须为每个槽位独立维护内部状态(如Transformer/RNN的KV Cache、累加器等)。这是最常用的有状态模型策略。 | 这是默认策略。模型可以通过CONTROL_SEQUENCE_START、CONTROL_SEQUENCE_READY等控制输入,精确知道每个槽位的状态。 |
| Oldest (最旧策略) | 不固定分配槽位,而是从候选序列池中,按请求到达的先后顺序(最旧的优先)挑选,动态组成一个批次进行推理。 | 动态复用。一个序列的不同请求可能会由不同的槽位处理。 | 模型不依赖固定槽位来维护状态,而是通过CONTROL_SEQUENCE_CORRID(关联ID)来识别请求属于哪个序列。或者状态由Triton的隐式状态管理来处理。 | 可以支持候选序列数(max_candidate_sequences)大于实际批处理大小(max_batch_size) 的情况。 |
总的来说,Direct策略通过固定的“批处理槽”,为有状态模型提供了最简单、最可靠的序列状态管理方式。这就像给每个对话任务安排一个专属的接待员,他能记住之前所有的对话内容,保证服务的连贯性。而Oldest策略则更像一个高效的呼叫中心,不设固定接待员,但通过来电显示(关联ID)来识别客户,同样能保证服务质量。