vLLM Rust Mock Engine:为前端压测而生的无头引擎模拟器(vllm-mock-engine)
2026/9/7 5:56:18 网站建设 项目流程

vLLM Rust Mock Engine:为前端压测而生的无头引擎模拟器(vllm-mock-engine)

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

本文围绕 vLLM 仓库中的 Mock Engine 文档 展开,讲解vllm-mock-engine这个面向前端(API Server)压力测试的独立进程:它如何通过 frontend 主导的 ZMQ 握手加入启动流程、上报大容量的 ready 响应、把 prefill 视为瞬时完成,并以随机 token 逐块输出直到每个请求达到max_tokens。读完本文,你可以用它配合 Rust 前端或 Pythonvllm serve前端拉起一条“免模型、免 GPU”的完整推理链路,对前端的请求路由、流式输出、DP 引擎调度等路径做可复现的压测与冒烟验证。

一、Mock Engine 定位:前端压测的“假引擎”

vllm-mock-engine是一个小型的 engine 侧进程,官方文档对其定位描述为“frontend stress testing”(前端压力测试)README。它不做任何真实推理,只模拟 vLLM engine core 的对外协议行为:

  • 加入 frontend 主导的启动握手(startup handshake):前端持有握手 socket,mock engine 作为客户端加入;
  • 上报大容量的 ready 响应:使前端认为引擎拥有足够的模型长度与调度容量;
  • 将 prefill 视为瞬时完成:不存在真实的计算耗时;
  • 按块随机输出 decode token,直到每个请求达到自身的max_tokens

它由 CLI 二进制vllm-mock-engine提供,对应 Cargo.toml 中的[[bin]]定义,依赖vllm-engine-core-clientzeromqclaptokio等 crate,即完整复用了 vLLM Rust 引擎客户端的协议栈与 ZMQ 传输层。

从源码结构看,进程入口在 main.rs:解析Opt参数、构建多线程 Tokio runtime、注册 Ctrl-C 信号后调用runshutdown_signal()CancellationTokentokio::signal::ctrl_c()绑定,因此文档中“Stop it with Ctrl-C”的行为由该信号处理直接保证。

二、启动 Mock Engine:命令与参数

2.1 基本启动命令

文档给出的标准启动方式为(参数与 lib.rs 中的 Opt 定义 一一对应):

cargo run -p vllm-mock-engine -- \ --handshake-address tcp://127.0.0.1:29550 \ --engine-count 1 \ --output-token-chunk-size 1 \ --vocab-size 32000 \ --seed 0 \ --log-requests

2.2 参数详解(含源码中的默认值)

结合 Opt 的 clap 定义,各参数的默认值与语义如下:

参数默认值语义
--handshake-addresstcp://127.0.0.1:29550frontend 持有的 ZMQ 握手地址,mock engine 必须用相同地址加入
--engine-count1向 frontend 注册的 mock engine 身份数量,必须与前端期望的>cargo run --bin vllm-rs -- serve Qwen/Qwen3-0.6B \ --data-parallel-size 1 \ --data-parallel-size-local 0 \ --handshake-port 29550

Terminal 2:

cargo run -p vllm-mock-engine -- \ --handshake-address tcp://127.0.0.1:29550

要点:--data-parallel-size-local 0表示本地不启动任何真实引擎,进程只做前端并等待外部引擎通过--handshake-port指定的端口加入。

3.2 Rust 前端(多引擎)

两侧必须使用相同数量(文档示例为 4):

cargo run --bin vllm-rs -- serve Qwen/Qwen3-0.6B \ --data-parallel-size 4 \ --data-parallel-size-local 0 \ --handshake-port 29550
cargo run -p vllm-mock-engine -- \ --handshake-address tcp://127.0.0.1:29550 \ --engine-count 4

此时 mock engine 进程内会同时运行 4 个引擎任务(见 lib.rs 的 run 函数),每个任务独立执行 IO 循环与引擎循环。

3.3 Python 前端

使用vllm serve并加--data-parallel-size-local 0,使 Python 进程只作为 frontend/API server,等待外部引擎出现在--data-parallel-rpc-port上:

Terminal 1:

vllm serve Qwen/Qwen3-0.6B \ --data-parallel-address 127.0.0.1 \ --data-parallel-rpc-port 29550 \ --data-parallel-size 1 \ --data-parallel-size-local 0

Terminal 2:

cargo run -p vllm-mock-engine -- \ --handshake-address tcp://127.0.0.1:29550

这一组合的意义在于:mock engine 协议兼容 Python 前端的 headless engine 握手路径,因此既可用于 Rust 前端开发测试,也可用于验证 Pythonvllm serve在“外部 headless 引擎”模式下的行为(例如 DP RPC 路由、流式响应)。

四、内部工作流:握手、IO 循环与引擎循环

以下结合 lib.rs、io.rs 与 engine.rs 说明一个 mock engine 实例的完整运行路径。

4.1 连接前端(connect_to_frontend)

每个 mock engine 任务调用 connect_to_frontend(vllm_engine_core_client::mock_engine),完成 INIT/READY 握手后拿到MockEngineSockets { init, data_sockets, coordinator }data_sockets是按 client-index 排序的 dealer/push socket 对:dealer 收前端请求,push 向对应前端客户端回送输出。对 Rust 前端通常只有一个 client socket;对 Python 前端,若存在多个 API server 进程,则会有多个 socket。

4.2 双任务结构:IO 循环 + 引擎循环

每个 mock engine 由两个 tokio 任务协作 lib.rs#L51-L109:

  1. IO 循环(io::run_io_loop):把所有 dealer socket 的输入流合并(stream::select_all),把输出按client_index路由到对应的 push socket。decode_request要求消息恰好 2 帧——第 0 帧是请求类型(Add/Abort/Utility/StartDpWave),第 1 帧是 msgpack 编码的负载;解码失败的消息仅告警并丢弃。
  2. 引擎循环(engine::run_engine_loop):维护active_requests哈希表,通过tokio::select!在“收到新输入”与“yield_now()后的 step”之间交替——只要存在活跃请求,每轮调度都推进一次 decode 步,从而在不阻塞输入处理的前提下稳定产出 token。

两个任务之间用mpsc通道(input 无界、output 容量 64)连接;任一任务异常退出时,tokio::select!会中止另一任务并向上返回错误,保证进程不会留下“半个引擎”。

4.3 请求生命周期

  • 请求进入EngineInput::Request):ActiveRequest::new 从EngineCoreRequest中读取prompt_token_ids长度与sampling_params.max_tokens。若缺少 sampling params 则立即返回EngineCoreFinishReason::Error的终止输出;max_tokens == 0时直接以Length结束;重复的 request_id 会收到 Error 终止输出并触发告警日志。
  • decode 步进(step):每步按 chunk size 从请求私有 RNG 中采样 token,generated累计;达到max_tokens时该输出携带finish_reason = Length,进入finished_requests集合,随后从活跃表中移除。
  • 中止EngineInput::Abort):按 request_id 从活跃表移除,向对应 client 回送Abort终止输出 engine.rs#L256-L292。
  • Utility 调用:对前端常用的控制方法返回最小可用结果(utility_response),例如get_supported_tasks返回["generate"]is_sleeping返回falsereset_prefix_cache返回truesleep/wake_up/profile等返回空结果;未知方法返回Nil
  • StartDpWave:直接忽略(打 debug 日志),因为 mock 引擎没有 DP 波次同步需求。

每次 step 产出的输出按client_index分组打包为RequestBatchOutputs(含engine_index、时间戳与finished_requests),这与真实 engine core 的批量输出形态保持一致,前端无需为 mock 场景做特殊分支。

五、冒烟验证:流式请求与max_tokens约束

任一端 frontend ready 之后,文档给出的冒烟请求为:

curl http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "Qwen/Qwen3-0.6B", "messages": [{"role": "user", "content": "hello"}], "max_tokens": 16, "stream": true }'

文档特别强调:必须传max_tokens,因为 mock engine 只按长度停止(stops by length)。这与实现一致——mock engine 唯一的自然终止条件是generated >= max_tokens(step 中的 Length 判定),不存在 EOS/stop-string 之类的语义终止。因此在压测脚本中应显式设置max_tokens,否则请求可能永远不结束。开启--log-requests后,每个请求会在控制台打印mock request started(含 prompt_len、max_tokens、chunk_size)与mock request finished(finish_reason=length)摘要行,便于核对请求是否被完整消费。

六、适用场景与限制

适用场景

  • Rust 前端(vllm-rs)开发期不加载模型、不占 GPU 的前端链路测试:握手、DP 路由、流式输出、abort 处理;
  • --output-token-chunk-size > 1构造 MTP/spec-decode 形态的多 token 输出,验证前端对一次多个 token 的输出路径;
  • --engine-count N模拟多 DP 引擎拓扑,验证前端的负载均衡与 client_index 输出路由;
  • --seed固定随机序列,使流式输出内容可复现,方便对比测试。

限制与适用前提

  • mock engine 仅模拟 engine-core 协议的“请求进、token 出”主干路径,token 为词表范围内随机值,语义上与模型输出无关;
  • ready 响应中的num_gpu_blocks = 0max_model_len = 1M等是测试常量(mock_engine.rs 顶部常量),只用于让前端放行,不代表真实容量;
  • 握手地址必须与前端一致且前端先启动;--engine-count与前端期望的 DP 引擎数不一致时前端无法进入 ready;
  • 需要cargo工具链在仓库根目录构建,命令均假定当前位于 vLLM 仓库根(rustworkspace 由根 Cargo.toml 管理)。

七、相关文件索引

  • 官方文档:rust/src/mock-engine/README.md
  • 参数解析与进程入口:rust/src/mock-engine/src/lib.rs、rust/src/mock-engine/src/main.rs
  • 引擎循环(请求/abort/utility 处理、随机 token 生成):rust/src/mock-engine/src/engine.rs
  • IO 循环(dealer/push 收发、msgpack 解码):rust/src/mock-engine/src/io.rs
  • 握手与 ready 响应辅助:rust/src/engine-core-client/src/mock_engine.rs
  • 单元测试:rust/src/mock-engine/src/tests.rs
  • 测试侧复用 mock engine 的入口:rust/src/engine-core-client/src/test_utils.rs

总结来说,vllm-mock-engine的价值在于把“前端 ↔ engine-core”的协议边界从真实推理中解耦出来:先起前端(Rust 或 Python,--data-parallel-size-local 0),再按相同握手地址启动 mock engine,用--engine-count/--output-token-chunk-size/--seed控制拓扑、输出形态与可复现性,然后用带max_tokens的流式请求即可完成端到端冒烟与压力验证。

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询