AIBrix 多引擎(Multi-Engine)支持实战指南:一套集群统一调度 vLLM、SGLang、xLLM 与 TRT-LLM
【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix
本文围绕 AIBrix 的多引擎调度(Multi-Engine Scheduling)能力展开,介绍如何在同一套 AIBrix 实例下同时部署 vLLM、SGLang、xLLM、TRT-LLM 等多种推理引擎,通过 Pod 标签(label)完成引擎识别与指标适配,并让路由策略(Router)基于各引擎真实导出的 Prometheus 指标做请求分发。读完本文,你将掌握model.aibrix.ai/engine系列标签的完整配置方法、跨引擎指标映射原理、TRT-LLM 的接入要点,以及如何为 AIBrix 扩展新的引擎类型。
为什么需要多引擎支持
在引入多引擎能力之前,AIBrix 在模型服务阶段只支持 vLLM 单一引擎。这带来的直接限制是:在同一个工作负载或基准测试(benchmarking)场景中,无法灵活地在不同引擎之间进行实验与对比。
多引擎支持为 AIBrix 带来了三方面价值:
- 并排对比(Side-by-side comparisons):在同一套集群中横向对比不同引擎的端到端延迟、吞吐与行为特征,为引擎选型提供一手数据;
- 部署灵活性(Deployment flexibility):支持模型分片(model sharding)或迁移策略,例如将部分流量导向 SGLang、部分导向 TRT-LLM;
- 指标适配(Metrics Adaptation):不同引擎导出的 Prometheus 指标名不同,AIBrix 通过统一的抽象指标名 + 引擎映射表来正确解读每种引擎的指标。
系统工作方式:标签驱动 + 指标映射
多引擎调度的核心设计是标签驱动:入站请求会借助 Deployment 上的标签,决定如何解读从 Prometheus API 拉取到的指标,而这些指标随后被 Router 用于请求委派(delegate execution)。
配置某个引擎时,只需在 Deployment 的 Pod 模板(template)上添加如下标签:
labels: model.aibrix.ai/name: deepseek-llm-7b-chat model.aibrix.ai/engine: "sglang" model.aibrix.ai/metric-port: "8000" # 当 Prometheus 端口与默认端口不同时配置 model.aibrix.ai/port: "8000"AIBrix 使用model.aibrix.ai/engine标签确定该 Deployment 使用哪个引擎,并据此在所有从 Prometheus 拉取的指标中查找正确的指标名格式。
目前支持的引擎标签取值为:vllm、sglang、xllm、trtllm。
完整工作流程(三步)
- Pod 监听与引擎识别:AIBrix 缓存(cache)监听携带
model.aibrix.ai/name标签的 Pod,并从同一 Pod 上读取model.aibrix.ai/engine。AIBrix 内部使用的每一个指标都有一个抽象名称(例如num_requests_waiting),并对应一张“引擎 → 引擎实际导出的指标名”的映射表,该映射定义在 pkg/metrics/metrics.go 中(完整映射见下文"跨引擎指标映射表"一节)。 - 指标抓取:指标从每个 Pod 的
model.aibrix.ai/metric-port端口(缺省为8000)的/metrics路径抓取;对于trtllm引擎,路径为/prometheus/metrics。请求则被转发到model.aibrix.ai/port端口。 - 路由策略取值与降级:路由策略向缓存请求抽象指标名。当某个引擎没有提供策略所需的指标映射时,大多数策略(
least-request、least-kv-cache、least-latency、least-busy-time、least-gpu-cache、least-util、throughput)会为该请求回退到随机 Pod;而 SLO 系列策略(slo-least-load、slo-pack-load、slo-least-load-pulling)则直接返回错误,该错误会以 HTTP 503 的形式呈现给客户端。
说明:可选的 runtime sidecar 是一套独立的机制,它会在自己的端口上以标准化形态重新导出引擎指标;引擎标签的使用并不依赖该 sidecar。
从源码看实现细节
在 pkg/cache/cache_metrics.go 中可以看到完整的数据通路:
- 常量
MetricPortLabel = constants.ModelLabelMetricPort、engineLabel = constants.ModelLabelEngine、defaultMetricPort = 8000、defaultEngineLabelValue = "vllm"(pkg/cache/cache_metrics.go)定义了标签与默认值; getPodMetricPort解析 Pod 的model.aibrix.ai/metric-port标签,解析失败或缺失时回退到默认端口8000(pkg/cache/utils.go);- 指标抓取工作线程
worker以pod.Status.PodIP:podMetricPort作为 endpoint,调用metrics.GetEngineType(*pod.Pod)获取引擎类型,再经FetchAllTypedMetrics统一抓取所有类型化指标(pkg/cache/cache_metrics.go); - 引擎指标路径由 pkg/metrics/engine_fetcher.go 的
metricsPathForEngine决定:trtllm使用prometheus/metrics,其余引擎统一使用metrics; - 当引擎指标自带
engine_type/model_name标签缺失或为undefined时,sanitizeMetricLabels会使用 Pod 标签(model.aibrix.ai/engine、model.aibrix.ai/name)回填,保证指标归属正确(pkg/cache/cache_metrics.go)。
所有标签键在 pkg/constants/model.go 中以常量形式统一声明:ModelLabelName、ModelLabelEngine、ModelLabelMetricPort、ModelLabelPort(pkg/constants/model.go),格式遵循resource.aibrix.ai/attribute约定。
配置参考:四个核心标签
多引擎的一切配置都通过 Pod 标签完成。注意:请将这些标签设置在Deployment的 Pod 模板(pod template)上(如果是 StormService,则设置在 role 上),而不是设置在 workload 对象(如 Deployment 本身)的 metadata 上——这与 samples/quickstart/tensorrt/tensor-rt.yaml 中的写法一致:Deployment 顶层metadata.labels只放app与模型名,model.aibrix.ai/engine放在spec.template.metadata.labels。
| 标签 | 默认值 | 含义 |
|---|---|---|
model.aibrix.ai/name | 必填 | 请求中使用的模型名,同时用于 Pod 发现。 |
model.aibrix.ai/engine | vllm | 引擎类型,取值为vllm、sglang、xllm、trtllm之一,决定选用哪张指标映射表。 |
model.aibrix.ai/port | 8000 | 引擎对外提供推理服务的端口。 |
model.aibrix.ai/metric-port | 8000 | 引擎暴露/metrics的端口;当指标端口与推理服务端口不同时配置(例如引擎与 HTTP 代理分离部署的场景,见 pkg/cache/cache_metrics.go 的注释)。 |
跨引擎指标映射表(Supported Metrics)
AIBrix 目前只支持各引擎有限数量的指标,且会持续扩充。对于通过 routing policy API 实现的路由算法(位于 pkg/plugins/gateway/algorithms),请确保使用的指标在你的目标引擎上受支持。如上文"工作流程"所述,大多数现有路由策略在无法获取目标指标时会回退到默认(随机)策略,SLO 系列策略除外。
下表完整列出了 AIBrix 抽象指标名到各引擎实际导出指标名的映射(N/A 表示该引擎不提供此指标):
| AIBrix 指标 | vLLM | SGLang | xLLM | TRT-LLM |
|---|---|---|---|---|
num_requests_running | vllm:num_requests_running | sglang:num_running_reqs | N/A | N/A |
num_requests_waiting | vllm:num_requests_waiting | sglang:num_queue_reqs | N/A | N/A |
num_requests_swapped | vllm:num_requests_swapped | sglang:num_retracted_reqs | N/A | N/A |
engine_sleep_state | vllm:engine_sleep_state | N/A | N/A | N/A |
http_requests_total | vllm:http_requests_total | N/A | N/A | N/A |
num_preemptions_total | vllm:num_preemptions_total | N/A | N/A | N/A |
request_success_total | vllm:num_requests_success_total | sglang:num_requests_total | N/A | trtllm_request_success_total |
num_prefill_prealloc_queue_reqs | N/A | sglang:num_prefill_prealloc_queue_reqs | N/A | N/A |
num_decode_prealloc_queue_reqs | N/A | sglang:num_decode_prealloc_queue_reqs | N/A | N/A |
e2e_request_latency_seconds | vllm:e2e_request_latency_seconds | sglang:e2e_request_latency_seconds | N/A | trtllm_e2e_request_latency_seconds |
request_queue_time_seconds | vllm:request_queue_time_seconds | N/A | N/A | trtllm_request_queue_time_seconds |
request_inference_time_seconds | vllm:request_inference_time_seconds | N/A | N/A | N/A |
per_stage_req_latency_seconds | N/A | sglang:per_stage_req_latency_seconds | N/A | N/A |
http_request_duration_seconds | http_request_duration_seconds | N/A | N/A | N/A |
http_request_duration_highr_seconds | http_request_duration_highr_seconds | N/A | N/A | N/A |
prompt_tokens_total | vllm:prompt_tokens_total | N/A | N/A | N/A |
request_prompt_tokens | vllm:request_prompt_tokens | N/A | N/A | N/A |
generation_tokens_total | vllm:generation_tokens_total | N/A | N/A | N/A |
request_generation_tokens | vllm:request_generation_tokens | N/A | N/A | N/A |
request_max_num_generation_tokens | vllm:request_max_num_generation_tokens | N/A | N/A | N/A |
iteration_tokens_total | vllm:iteration_tokens_total | N/A | N/A | N/A |
time_to_first_token_seconds | vllm:time_to_first_token_seconds | sglang:time_to_first_token_seconds | N/A | trtllm_time_to_first_token_seconds |
time_per_output_token_seconds | vllm:time_per_output_token_seconds | sglang:inter_token_latency_seconds | N/A | trtllm_time_per_output_token_seconds |
inter_token_latency_seconds | vllm:inter_token_latency_seconds | sglang:inter_token_latency_seconds | N/A | trtllm_time_per_output_token_seconds |
request_decode_time_seconds | vllm:request_decode_time_seconds | N/A | N/A | N/A |
request_prefill_time_seconds | vllm:request_prefill_time_seconds | N/A | N/A | N/A |
request_time_per_output_token_seconds | vllm:request_time_per_output_token_seconds | N/A | N/A | N/A |
gpu_cache_usage_perc | vllm:gpu_cache_usage_perc | sglang:token_usage | kv_cache_utilization | N/A |
engine_utilization | N/A | N/A | engine_utilization | N/A |
cpu_cache_usage_perc | vllm:cpu_cache_usage_perc | N/A | N/A | N/A |
kv_cache_usage_perc | vllm:kv_cache_usage_perc | sglang:token_usage | kv_cache_utilization | trtllm_kv_cache_utilization |
kv_cache_hit_rate | N/A | N/A | N/A | trtllm_kv_cache_hit_rate |
prefix_cache_queries_total | vllm:prefix_cache_queries_total | N/A | N/A | N/A |
prefix_cache_hits_total | vllm:prefix_cache_hits_total | N/A | N/A | N/A |
external_prefix_cache_queries_total | vllm:external_prefix_cache_queries_total | N/A | N/A | N/A |
external_prefix_cache_hits_total | vllm:external_prefix_cache_hits_total | N/A | N/A | N/A |
nixl_xfer_time_seconds | vllm:nixl_xfer_time_seconds | N/A | N/A | N/A |
nixl_post_time_seconds | vllm:nixl_post_time_seconds | N/A | N/A | N/A |
nixl_bytes_transferred | vllm:nixl_bytes_transferred | N/A | N/A | N/A |
nixl_num_descriptors | vllm:nixl_num_descriptors | N/A | N/A | N/A |
nixl_num_failed_transfers_total | vllm:nixl_num_failed_transfers | N/A | N/A | N/A |
nixl_num_failed_notifications_total | vllm:nixl_num_failed_notifications | N/A | N/A | N/A |
avg_prompt_throughput_toks_per_s | vllm:avg_prompt_throughput_toks_per_s | N/A | N/A | N/A |
avg_generation_throughput_toks_per_s | vllm:avg_generation_throughput_toks_per_s | sglang:gen_throughput | N/A | N/A |
max_lora | vllm:lora_requests_info | N/A | N/A | N/A |
running_lora_adapters | vllm:lora_requests_info | N/A | N/A | N/A |
waiting_lora_adapters | vllm:lora_requests_info | N/A | N/A | N/A |
补充说明两点:
- SGLang 的
gpu_cache_usage_perc与kv_cache_usage_perc均映射到sglang:token_usage,这一点在 pkg/metrics/metrics.go 与 pkg/metrics/metrics.go 的源码注释中也有明确标注(// Based on ...)。 time_per_output_token_seconds在 AIBrix 内部已被标记为 deprecated,推荐使用inter_token_latency_seconds替代(见 pkg/metrics/metrics.go 的注释),但两者的引擎映射均被保留以兼容现有策略。
指标的类型化抓取
从源码看,AIBrix 将指标分为三类分别抓取(pkg/cache/cache_metrics.go):
- counter/gauge 类(
counterGaugeMetricNames):如num_requests_running、kv_cache_usage_perc等,直接读取原始值; - histogram 类(
histogramMetricNames):如time_to_first_token_seconds、e2e_request_latency_seconds等,涉及_sum/_bucket/_count序列; - PromQL 查询类(
prometheusMetricNames):如P95TTFT5m、AvgRequestsPerMinPod等,需要在 pkg/metrics/metrics.go 中预定义 PromQL 模板,再由缓存按instance、model_name标签实时查询。
需要留意的是,部分 PromQL 查询类指标(例如P95TTFT5m)的模板目前仍硬编码引用vllm:前缀的指标名,源码中以// TODO: make it agnostic to the engine(pkg/metrics/metrics.go)标注了待办——也就是说,原始指标(raw metric)已完全引擎无关化,但少量查询类指标的引擎无关化仍在推进中。
TRT-LLM 快速上手
将 TRT-LLM 作为推理引擎时,在 Deployment 上设置model.aibrix.ai/engine: trtllm标签即可。TRT-LLM 必须在服务端配置中显式开启性能指标暴露:return_perf_metrics: true、enable_iter_perf_stats: true、enable_iter_req_stats: true。
官方示例配置位于:
- samples/quickstart/tensorrt/tensor-rt.yaml — 标准单实例部署;
- samples/quickstart/tensorrt/tensor-rt-pd.yaml — 基于 StormService 的 prefill/decode 分离部署。
TRT-LLM 的部署标签配置示例:
labels: model.aibrix.ai/name: Qwen3-8B model.aibrix.ai/engine: trtllm model.aibrix.ai/port: "8000"参考 samples/quickstart/tensorrt/tensor-rt.yaml 的完整写法,一个可运行的 TRT-LLM Deployment 形如:
apiVersion: apps/v1 kind: Deployment metadata: name: qwen-tensorrt-llm labels: app: qwen-llm model.aibrix.ai/name: Qwen3-8B model.aibrix.ai/port: "8000" spec: replicas: 1 selector: matchLabels: app: qwen-llm template: metadata: labels: app: qwen-llm model.aibrix.ai/name: Qwen3-8B model.aibrix.ai/port: "8000" model.aibrix.ai/engine: trtllm spec: containers: - name: tensorrt-llm image: <tensorrt-llm 镜像> command: ["/bin/bash", "-c"] args: - | cat <<'EOF' > /tmp/config.yaml backend: pytorch kv_cache_config: free_gpu_memory_fraction: 0.85 max_num_tokens: 8192 max_batch_size: 16 trust_remote_code: true return_perf_metrics: true enable_iter_perf_stats: true enable_iter_req_stats: true perf_metrics_max_requests: 1000 EOF trtllm-serve serve /models/Qwen3-8B \ --host 0.0.0.0 \ --port 8000 \ --extra_llm_api_options /tmp/config.yaml ports: - containerPort: 8000 resources: limits: nvidia.com/gpu: 1 requests: nvidia.com/gpu: 1注意model.aibrix.ai/engine: trtllm位于spec.template.metadata.labels(Pod 模板),而model.aibrix.ai/name同时出现在 Deployment 顶层 metadata 与 Pod 模板上——这与前文"标签应设置在 Pod 模板上"的约定一致。
TRT-LLM 的已知限制
- 没有队列深度指标:TRT-LLM 不暴露
num_requests_running或num_requests_waiting。依赖队列深度的路由策略(例如least-request)将回退到随机路由(fall back to random routing)。 - 指标依赖显式配置:只有当 TRT-LLM 服务端配置设置了
return_perf_metrics: true、enable_iter_perf_stats: true、enable_iter_req_stats: true时,性能指标才会被导出。 - 指标路径不同:TRT-LLM 的指标抓取路径是
/prometheus/metrics而非/metrics,该逻辑由 pkg/metrics/engine_fetcher.go 的metricsPathForEngine统一处理,用户无需额外配置。
如何新增引擎(Adding New Engines)
若要支持一个新的引擎或新的指标类型,需要完成两步:
- 在指标名映射表中添加引擎类型:修改 pkg/metrics/metrics.go 中
EngineMetricsNameMapping映射(例如为某个指标增加"newengine": "newengine:some_metric"条目),并补充引擎名常量(参考EngineNameVLLM、EngineNameSGLang、EngineNameTRTLLM的定义,pkg/metrics/metrics.go); - 在 Deployment YAML 中允许新的引擎标签值:在
model.aibrix.ai/engine标签上使用新引擎名。
更完整的实现细节可参考:
- pkg/cache/cache_metrics.go — 指标抓取、调度、回退与标签清洗逻辑;
- pkg/metrics/metrics.go — 指标注册表与引擎名映射。
从代码结构看,指标抓取层(EngineMetricsFetcher.FetchAllTypedMetrics)已经按"引擎类型 → 指标路径/映射"做了抽象(pkg/metrics/engine_fetcher.go),因此新增引擎时主要工作集中在映射表补充与标签值合法化,无需改动路由策略本身——这也是多引擎设计"即插即用"的关键所在。
小结
AIBrix 的多引擎支持通过"Pod 标签识别引擎 + 抽象指标名统一映射 + 路由策略自动降级"三层机制,让开发者在同一套集群内自由混排 vLLM、SGLang、xLLM 与 TRT-LLM 等引擎,既可用于引擎横向对比与基准测试,也可服务于模型分片与迁移等生产场景。接入新引擎时,只需补齐 pkg/metrics/metrics.go 中的指标映射并在 Deployment 上声明引擎标签,即可复用现有的缓存抓取与路由调度体系。
【免费下载链接】aibrixCost-efficient and pluggable Infrastructure components for GenAI inference项目地址: https://gitcode.com/GitHub_Trending/ai/aibrix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考