一个请求的一生
主线位置:整条「一个请求的一生」。这一部分把 HTTP 进来、模板与分词、调度、前向与采样、反分词、流式返回串成一条线,标出每一段在哪个进程、由什么语言实现;调度和 KV 的内部只点到为止,留给 02、03。
版本:vLLM v0.32.0、SGLang v0.5.22
两个引擎都把「CPU 上的文本处理」和「GPU 上的调度与前向」拆进不同的进程,用 ZMQ 连起来。拆法不同:
| vLLM v0.32.0(单卡默认) | SGLang v0.5.22(单卡默认) | |
|---|---|---|
| 进程 | 2 个:API server、EngineCore | 3 个:主进程、Scheduler、DetokenizerManager |
| HTTP、模板、分词 | API server(Python) | 主进程(Python) |
| 调度、前向、采样 | EngineCore(Python 调 CUDA) | Scheduler(Python 调 CUDA) |
| 反分词 | API server(Python) | DetokenizerManager(Python) |
| 通道 | 一对 ZMQ:ROUTER↔DEALER 进,PUSH→PULL 出 | 三段 ZMQ PUSH→PULL 首尾相接成环 |
| 序列化 | msgpack(msgspec) | 默认 pickle,可切 msgpack |
| 换成 Rust | VLLM_USE_RUST_FRONTEND=1:整个 API server 换成独立的 Rust 进程,EngineCore 不变 | SGLANG_RUST_SERVER=1:HTTP、分词、反分词变成 Rust 线程,嵌进调度器进程 |
- vLLM:API server 与 EngineCore:默认路径两个进程上的每一步和源文件;分词放在线程池里,反分词在 API server 的事件循环里做;EngineCore 用两个 IO 线程把 ZMQ 收发和 GPU 步重叠;打开 Rust 前端后,Python 主进程退成看守,HTTP 到反分词整段由
vllm-rs接手。 - SGLang:TokenizerManager、Scheduler、DetokenizerManager:默认路径三个进程首尾相接;聊天模板和分词在主进程的事件循环里同步做;调度器默认走重叠循环;反分词单独一个进程,按批解码;打开 Rust 服务后,主进程只剩等待,调度器进程里多出一组 Rust 线程,进出都走进程内的 flume 通道。
两种 Rust 集成方式的对比、各自覆盖哪些接口,在 两种 Rust 前端。
flowchart TB
subgraph V["vLLM 默认"]
va["API server<br/>Python"] -->|"ZMQ ROUTER→DEALER<br/>msgpack"| ve["EngineCore<br/>Python + CUDA"]
ve -->|"ZMQ PUSH→PULL<br/>msgpack"| va
end
subgraph S["SGLang 默认"]
sm["主进程<br/>HTTP + TokenizerManager<br/>Python"] -->|"ZMQ PUSH→PULL"| ss["Scheduler<br/>Python + CUDA"]
ss -->|"ZMQ PUSH→PULL"| sd["DetokenizerManager<br/>Python"]
sd -->|"ZMQ PUSH→PULL"| sm
end
💬 关联讨论
发起讨论加载中...