大模型推理框架的选型直接影响服务稳定性、推理成本和运维复杂度。SGLang、vLLM 和 TensorRT-LLM 是当前主流的三种推理服务框架,各有侧重:
选型时不能只看 benchmark 数据,还要结合运维实际场景:服务可用性、故障恢复能力、监控可观测性、资源利用率和扩展性。本文从运维视角出发,提出五个核心问题,帮助你在选型前做出更准确的判断。
本文适用于以下角色和场景:
涉及的技术栈:
vLLM 架构特点:
SGLang 架构特点:
TensorRT-LLM 架构特点:
| 框架 | 显存管理方式 | KV Cache 策略 | 碎片率 |
|---|---|---|---|
| vLLM | PagedAttention | 动态分配,块管理 | 低 |
| SGLang | PagedAttention + RadixCache | prefix 缓存复用 | 低 |
| TensorRT-LLM | Inflight Batching | 固定预分配 | 中 |
推理服务进程因 OOM、CUDA 错误、异常请求、依赖故障等原因崩溃。Kubernetes 或 Docker 自动重启容器,但模型加载需要时间。这段时间内:
vLLM:
模型加载时间取决于模型大小和磁盘 I/O:
启动流程:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --gpu-memory-utilization 0.9 --max-model-len 4096 观察启动日志:
INFO: Started server process INFO: Waiting for application startup. INFO: Loading model weights... INFO: Model loaded successfully INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000
关键时间点:Model loaded successfully 到 Application startup complete 之间的时间。
健康检查配置:
yaml
livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /v1/models port: 8000 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 2 推理服务进程因 OOM、CUDA 错误、异常请求、依赖故障等原因崩溃。Kubernetes 或 Docker 自动重启容器,但模型加载需要时间。这段时间内:
vLLM:
模型加载时间取决于模型大小和磁盘 I/O:
启动流程:
bash
# vLLM 启动命令 python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --gpu-memory-utilization 0.9 --max-model-len 4096 观察启动日志:
INFO: Started server process INFO: Waiting for application startup. INFO: Loading model weights... INFO: Model loaded successfully INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000
关键时间点:Model loaded successfully 到 Application startup complete 之间的时间。
健康检查配置:
yaml
livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /v1/models port: 8000 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 2 SGLang:
除模型加载外,还需考虑 RadixCache 预热:
启动命令:
bash
python -m sglang.launch_server --model-path /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --mem-fraction-static 0.8 --max-running-requests 256 观察缓存状态:
bash
# SGLang 提供的缓存统计接口 curl http://localhost:8000/get_server_info | jq .cache_info 输出示例:
json
{ "cache_hit_rate": 0.0, "cache_total_tokens": 0, "cache_used_tokens": 0 }
服务重启后,cache_hit_rate 从 0 开始,需要一定时间恢复到稳态。
TensorRT-LLM:
启动流程最复杂:
编译时间(首次):
加载时间(已编译):
启动命令:
bash
# 使用 Triton Inference Server docker run --gpus all --rm -it -v /models:/models -p 8000:8000 -p 8001:8001 -p 8002:8002 nvcr.io/nvidia/tritonserver:24.01-trtllm-python-py3 tritonserver --model-repository=/models/trtllm_repo 观察就绪状态:
bash
# Triton 健康检查 curl -v http://localhost:8000/v2/health/ready 返回 200 表示就绪。
健康检查配置:
yaml
readinessProbe: httpGet: path: /v2/health/ready port: 8000 initialDelaySeconds: 120 # TensorRT-LLM 需要更长启动时间 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 | 框架 | 模型大小 | 冷启动时间 | 热重启时间 | 缓存恢复时间 |
|---|---|---|---|---|
| vLLM | 13B | 15s | 15s | 无 |
| vLLM | 70B | 45s | 45s | 无 |
| SGLang | 13B | 15s | 15s | 2-5 分钟 |
| SGLang | 70B | 45s | 45s | 5-10 分钟 |
| TensorRT-LLM | 13B | 30s | 30s | 无 |
| TensorRT-LLM | 70B | 90s | 90s | 无 |
vLLM:
initialDelaySeconds 设置为模型加载时间 + 10 秒/health 做 liveness,/v1/models 做 readinessSGLang:
TensorRT-LLM:
initialDelaySeconds 至少设置为 120 秒除模型加载外,还需考虑 RadixCache 预热:
启动命令:
bash
python -m sglang.launch_server --model-path /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --mem-fraction-static 0.8 --max-running-requests 256 观察缓存状态:
bash
curl http://localhost:8000/get_server_info | jq .cache_info 输出示例:
json
{ "cache_hit_rate": 0.0, "cache_total_tokens": 0, "cache_used_tokens": 0 }
服务重启后,cache_hit_rate 从 0 开始,需要一定时间恢复到稳态。
SGLang:
除模型加载外,还需考虑 RadixCache 预热:
启动命令:
bash
python -m sglang.launch_server --model-path /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --mem-fraction-static 0.8 --max-running-requests 256 观察缓存状态:
bash
curl http://localhost:8000/get_server_info | jq .cache_info 输出示例:
json
{ "cache_hit_rate": 0.0, "cache_total_tokens": 0, "cache_used_tokens": 0 }
服务重启后,cache_hit_rate 从 0 开始,需要一定时间恢复到稳态。
TensorRT-LLM:
启动流程最复杂:
编译时间(首次):
加载时间(已编译):
启动命令:
bash
docker run --gpus all --rm -it -v /models:/models -p 8000:8000 -p 8001:8001 -p 8002:8002 nvcr.io/nvidia/tritonserver:24.01-trtllm-python-py3 tritonserver --model-repository=/models/trtllm_repo 观察就绪状态:
bash
curl -v http://localhost:8000/v2/health/ready 返回 200 表示就绪。
健康检查配置:
yaml
readinessProbe: httpGet: path: /v2/health/ready port: 8000 initialDelaySeconds: 120 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 | 框架 | 模型大小 | 冷启动时间 | 热重启时间 | 缓存恢复时间 |
|---|---|---|---|---|
| vLLM | 13B | 15s | 15s | 无 |
| vLLM | 70B | 45s | 45s | 无 |
| SGLang | 13B | 15s | 15s | 2-5 分钟 |
| SGLang | 70B | 45s | 45s | 5-10 分钟 |
| TensorRT-LLM | 13B | 30s | 30s | 无 |
| TensorRT-LLM | 70B | 90s | 90s | 无 |
实测环境:
测试方法:
bash
# 记录启动时间 time kubectl rollout restart deployment/vllm -n inference # 观察 Pod 状态变化 kubectl get pods -n inference -w # 记录从 Terminating 到 Running 的时间 观察要点:
vLLM:
initialDelaySeconds 设置为模型加载时间 + 10 秒/health 做 liveness,/v1/models 做 readinessyaml
livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /v1/models port: 8000 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 2 SGLang:
yaml
readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 45 periodSeconds: 5 successThreshold: 2
使用 successThreshold: 2 确保服务稳定后再接入流量。
TensorRT-LLM:
initialDelaySeconds 至少设置为 120 秒yaml
readinessProbe: httpGet: path: /v2/health/ready port: 8000 initialDelaySeconds: 120 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 模拟服务崩溃:
bash
# 找到推理服务进程 ps aux | grep vllm # 强制杀死进程 kill -9 观察 Kubernetes 重启行为:
bash
# 实时查看 Pod 状态 kubectl get pods -w -n inference # 查看事件 kubectl describe pod -n inference 观察流量切换:
bash
# 查看 Service Endpoints kubectl get endpoints -n inference -o yaml # 持续发送请求,观察错误率 while true; do curl -s -o /dev/null -w "%{http_code} " http://:8000/v1/models sleep 1 done 正常情况下:
Not Ready 状态持续时间应等于 initialDelaySeconds + 首次健康检查成功时间异常情况:
initialDelaySeconds 过短:流量打到未就绪实例,返回 502/503failureThreshold 过大:故障节点摘除时间过长验证脚本:
bash
#!/bin/bash POD_NAME="vllm-7d6f4b8c9-xyz" NAMESPACE="inference" SERVICE_NAME="vllm-service" echo "Killing pod $POD_NAME..." kubectl delete pod "$POD_NAME" -n "$NAMESPACE" & sleep 5 echo "Monitoring endpoint changes..." kubectl get endpoints "$SERVICE_NAME" -n "$NAMESPACE" -w & echo "Sending test requests..." while true; do RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://vllm-service.inference.svc.cluster.local:8000/v1/models) TIMESTAMP=$(date +%T) echo "$TIMESTAMP: $RESPONSE" if [ "$RESPONSE" != "200" ]; then echo " ERROR DETECTED" fi sleep 1 done 预期输出:
1030: 200 1031: 200 1032: 503 ERROR DETECTED 1033: 503 ERROR DETECTED 1034: 503 ERROR DETECTED ... 1015: 200 1016: 200
503 错误持续时间应在 30-60 秒之间(取决于 initialDelaySeconds 配置)。
分离 Liveness 和 Readiness:
vLLM 配置示例:
yaml
livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /v1/models port: 8000 initialDelaySeconds: 30 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 2 区别:
failureThreshold 更大,避免频繁重启periodSeconds 更短,更快发现服务不可用initialDelaySeconds 更长,给模型加载足够时间自定义健康检查脚本:
对于复杂场景,可以编写自定义健康检查:
bash
#!/bin/bash check_gpu() { nvidia-smi > /dev/null 2>&1 return $? } check_model_loaded() { curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/v1/models | grep -q "200" return $? } check_memory() { used=$(nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits) total=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits) ratio=$(echo "scale=2; $used / $total" | bc) if (( $(echo "$ratio > 0.98" | bc -l) )); then return 1 fi return 0 } check_cache_hit_rate() { hit_rate=$(curl -s http://localhost:8000/get_server_info | jq -r '.cache_info.cache_hit_rate // 0') uptime=$(awk '{print int($1)}' /proc/uptime) if [ "$uptime" -gt 300 ] && (( $(echo "$hit_rate < 0.2" | bc -l) )); then echo "Cache hit rate too low: $hit_rate" return 1 fi return 0 } if ! check_gpu; then echo "GPU check failed" exit 1 fi if ! check_model_loaded; then echo "Model not loaded" exit 1 fi if ! check_memory; then echo "Memory usage too high" exit 1 fi echo "Health check passed" exit 0 Kubernetes 中使用:
yaml
livenessProbe: exec: command: - /scripts/health_check.sh initialDelaySeconds: 60 periodSeconds: 10 timeoutSeconds: 10 failureThreshold: 3 注意:
推理服务停止时,需要确保正在处理的请求完成,而不是直接杀死进程。
vLLM 支持 SIGTERM 信号进行优雅关闭:
bash
# 发送 SIGTERM 信号 kill -TERM # 观察日志 tail -f /var/log/vllm/server.log Kubernetes 中配置优雅关闭时间:
yaml
spec: terminationGracePeriodSeconds: 60 containers: - name: vllm lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 10"] 这样在 Pod 终止前,会先等待 10 秒让服务自行清理,然后再发送 SIGTERM。
观察优雅关闭日志:
bash
docker logs -- tail 50 -f 应该看到类似输出:
INFO: Shutting down INFO: Waiting for application shutdown. INFO: Draining 5 in-flight requests... INFO: Request 1/5 completed INFO: Request 2/5 completed INFO: Request 3/5 completed INFO: Request 4/5 completed INFO: Request 5/5 completed INFO: Application shutdown complete. INFO: Finished server process 优雅关闭时间线:
如果超过 terminationGracePeriodSeconds,Kubernetes 会发送 SIGKILL 强制杀死进程。
验证优雅关闭:
bash
#!/bin/bash POD_NAME="vllm-7d6f4b8c9-xyz" NAMESPACE="inference" echo "Sending requests in background..." for i in {1..10}; do curl -X POST http://vllm-service.inference.svc.cluster.local:8000/v1/completions -H "Content-Type: application/json" -d '{"model":"llama2-13b","prompt":"长文本生成测试","max_tokens":1024}' & done sleep 5 echo "Deleting pod..." kubectl delete pod "$POD_NAME" -n "$NAMESPACE" echo "Waiting for requests to complete..." wait echo "All requests completed" 如果优雅关闭生效,所有请求应该成功返回结果。
服务启动前,检查依赖是否满足:
bash
#!/bin/bash set -e echo "=== Pre-start Checks ===" echo "Checking CUDA environment..." if ! nvidia-smi > /dev/null 2>&1; then echo "ERROR: nvidia-smi not found or GPU not available" exit 1 fi gpu_count=$(nvidia-smi --list-gpus | wc -l) echo "Found $gpu_count GPU(s)" echo "Checking model files..." if [ ! -d "/models/Llama-2-13b-chat-hf" ]; then echo "ERROR: Model directory not found" exit 1 fi required_files=("config.json" "pytorch_model.bin" "tokenizer.json" "tokenizer_config.json") for file in "${required_files[@]}"; do if [ ! -f "/models/Llama-2-13b-chat-hf/$file" ]; then echo "ERROR: Required file $file not found" exit 1 fi done echo "Model files OK" echo "Checking disk space..." available=$(df -BG /models | tail -1 | awk '{print $4}' | sed 's/G//') if [ "$available" -lt 50 ]; then echo "WARNING: Low disk space: ${available}GB" fi echo "Checking GPU memory..." free_mem=$(nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits | head -1) if [ "$free_mem" -lt 20000 ]; then echo "ERROR: Insufficient GPU memory: ${free_mem}MB (need at least 20000MB)" exit 1 fi echo "GPU memory OK: ${free_mem}MB available" echo "Checking GPU driver version..." driver_version=$(nvidia-smi --query-gpu=driver_version --format=csv,noheader | head -1) echo "Driver version: $driver_version" if [[ "$driver_version" < "530.30.02" ]]; then echo "WARNING: Driver version may not support CUDA 12.1" fi echo "Checking CUDA version..." cuda_version=$(nvcc --version | grep release | awk '{print $5}' | sed 's/,//') echo "CUDA version: $cuda_version" echo "Checking Python environment..." if ! python -c "import torch; print(torch.cuda.is_available())" | grep -q "True"; then echo "ERROR: PyTorch CUDA not available" exit 1 fi echo "PyTorch CUDA OK" echo "Checking vLLM installation..." if ! python -c "import vllm" 2>/dev/null; then echo "ERROR: vLLM not installed" exit 1 fi echo "vLLM installed OK" echo "=== All checks passed ===" echo "Starting vLLM server..." exec python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --host 0.0.0.0 --port 8000 --gpu-memory-utilization 0.9 --max-model-len 4096 将此脚本作为容器启动命令:
yaml
containers: - name: vllm image: vllm/vllm-openai:latest command: ["/scripts/start_with_checks.sh"] volumeMounts: - name: models mountPath: /models - name: scripts mountPath: /scripts 这样可以在启动失败时快速定位原因。
推理服务运行过程中,显存占用受以下因素影响:
当并发请求数增加或出现超长序列时,显存可能耗尽。此时服务可能:
vLLM:
vLLM 启动时通过 --gpu-memory-utilization 参数控制显存使用上限:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --gpu-memory-utilization 0.9 观察显存使用:
bash
nvidia-smi --query-gpu=index,name,memory.used,memory.total --format=csv -l 1 curl http://localhost:8000/metrics | grep vllm_gpu_cache 关键指标:
vllm_gpu_cache_usage_perc{gpu="0"} 0.85 vllm_num_requests_running 12 vllm_num_requests_waiting 3
当 vllm_gpu_cache_usage_perc 接近 1.0 时,服务开始拒绝新请求。
拒绝请求时的日志:
WARNING: Request rejected due to insufficient KV cache space 客户端收到:
json
{ "error": { "message": "No available slots for new requests", "type": "service_unavailable" } } 显存占用构成:
总显存 = 模型权重 + KV Cache + 临时变量 + 系统开销 以 Llama-2-13B 为例(FP16):
max_model_len 和 max_num_seqs计算 KV Cache 大小:
KV Cache = 2 × num_layers × hidden_size × max_model_len × max_num_seqs × sizeof(dtype) 对于 Llama-2-13B(40 层,5120 hidden size):
KV Cache = 2 × 40 × 5120 × 4096 × 32 × 2 bytes = 107GB
这显然超过了单卡显存,所以 vLLM 会根据实际可用显存动态调整 max_num_seqs。
查看 vLLM 实际分配的 KV Cache 块数:
bash
curl http://localhost:8000/metrics | grep vllm_num_gpu_blocks 输出:
vllm_num_gpu_blocks{gpu="0"} 2048
每个块的大小取决于 block_size 参数(默认 16)。
SGLang 的显存管理类似 vLLM,但增加了 RadixCache:
bash
python -m sglang.launch_server --model-path /models/Llama-2-13b-chat-hf --mem-fraction-static 0.8 --mem-fraction-static:静态分配的显存比例(模型权重 + RadixCache)显存不足时的策略:
观察缓存驱逐:
bash
curl http://localhost:8000/get_server_info | jq .cache_info 输出:
json
{ "cache_hit_rate": 0.75, "cache_eviction_count": 128, "cache_total_tokens": 1048576, "cache_used_tokens": 921600 }
cache_eviction_count 增加表示发生了缓存驱逐。
TensorRT-LLM 使用固定大小的 KV Cache 预分配:
json
{ "max_batch_size": 32, "max_input_len": 2048, "max_output_len": 2048, "max_beam_width": 1 } max_batch_size 或序列长度超过 max_input_len 时,排队等待或拒绝观察请求排队:
bash
curl http://localhost:8002/metrics | grep nv_inference_queue_duration_us 输出:
nv_inference_queue_duration_us{model="llama2_13b",version="1"} 12500 排队时间过长表示并发能力不足。
| 框架 | OOM 风险 | 降级策略 | 客户端感知 | 恢复时间 |
|---|---|---|---|---|
| vLLM | 中 | 拒绝新请求 | 503 错误 | 立即 |
| SGLang | 低 | 驱逐缓存 + 拒绝请求 | 缓存命中率下降 + 503 | 数分钟 |
| TensorRT-LLM | 低 | 请求排队 | 延迟增加 | 无需恢复 |
压测场景:
bash
echo "POST http://localhost:8000/v1/completions" | vegeta attack -duration=60s -rate=50/s -body='{"model":"llama2-13b","prompt":"介绍一下北京","max_tokens":1024}' -header="Content-Type: application/json" | tee results.bin | vegeta report 观察显存使用变化:
bash
nvidia-smi dmon -s mu -c 60 输出示例:
# gpu mclk pclk sm mem enc dec # Idx MHz MHz % % % % 0 1215 1410 85 92 0 0 0 1215 1410 88 95 0 0 0 1215 1410 90 98 0 0
当 mem 列接近 100% 时,观察服务行为。
vLLM 表现:
查看日志:
bash
docker logs -- tail 100 -f 日志中出现:
WARNING: KV cache is full, rejecting new requests 客户端收到 503 错误率上升:
Requests [total, rate] 3000, 50.00 Duration [total] 60s Latencies [mean, 50, 95, 99] 456ms, 412ms, 892ms, 1.2s Success [ratio] 90.5% Status Codes [code:count] 200:2715 503:285 SGLang 表现:
类似 vLLM,但缓存驱逐后缓存命中率下降:
bash
curl http://localhost:8000/get_server_info | jq .cache_info.cache_hit_rate 输出从 0.75 降到 0.42。
TensorRT-LLM 表现:
请求排队,延迟增加:
Latencies [mean, 50, 95, 99] 1.2s, 980ms, 2.8s, 4.5s Success [ratio] 100% 成功率 100%,但 P95/P99 延迟明显升高。
调整并发数限制:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --max-num-seqs 16
减少 --max-num-seqs 可以降低 KV Cache 占用,但会降低吞吐量。
调整序列长度限制:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --max-model-len 2048
减少 --max-model-len 可以降低 KV Cache 占用。
使用量化模型:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-13b-chat-hf --quantization awq AWQ/GPTQ 量化可以将模型权重从 FP16 降到 INT4,显著降低显存占用。
量化后的显存占用:
但量化会带来精度损失和额外的计算开销。
使用 Tensor Parallel:
对于大模型,使用多 GPU 分摊显存:
bash
python -m vllm.entrypoints.openai.api_server --model /models/Llama-2-70b-chat-hf --tensor-parallel-size 4 70B 模型需要约 140GB 显存,使用 4 张 A100 可以容纳。
vLLM:
vllm_gpu_cache_usage_perc,超过 0.9 时触发告警--max-model-len 限制最大序列长度--max-num-seqs 限制最大并发数--gpu-memory-utilization 0.85,留出更多缓冲SGLang:
--mem-fraction-staticTensorRT-LLM:
max_batch_size 和 max_input_len 配置通用建议:
推理服务性能不佳时,可能的瓶颈:
GPU 指标:
bash
nvidia-smi dmon -s pucvmet -c 60 输出:
# gpu pwr gtemp mtemp sm mem enc dec mclk pclk # Idx W C C % % % % MHz MHz 0 280 72 - 95 85 0 0 1215 1410 关键列:
sm:GPU 计算利用率mem:显存控制器利用率pwr:功耗gtemp:GPU 温度显存占用:
bash
nvidia-smi --query-gpu=index,memory.used,memory.total,utilization.gpu,utilization.memory --format=csv -l 1 进程级显存占用:
bash
nvidia-smi pmon -c 60 CPU 利用率:
bash
top -b -n 1 | grep python ps aux | grep python | awk '{print $3, $4, $11}' 磁盘 I/O:
bash
iostat -x 1 输出:
Device r/s w/s rkB/s wkB/s %util nvme0n1 15.00 2.00 1920.00 64.00 8.50 关键列:
r/s, w/s:每秒读写次数rkB/s, wkB/s:每秒读写 KB 数%util:设备利用率网络 I/O:
bash
iftop -i eth0 nethogs 显存瓶颈:
memory.used 接近 memory.totalvllm_gpu_cache_usage_perc 接近 1.0计算瓶颈:
utilization.gpu 持续 > 90%sm 持续 > 90%I/O 瓶颈:
%util 高,rkB/s 高CPU 瓶颈:
案例一:显存瓶颈
现象:
bash
curl http://localhost:8000/metrics | grep vllm_gpu_cache_usage_perc vllm_gpu_cache_usage_perc{gpu="0"} 0.98 nvidia-smi --query-gpu=memory.used,memory.total --format=csv memory.used [MiB], memory.total [MiB] 79872 MiB, 81920 MiB 日志:
WARNING: KV cache is full, rejecting new requests 判断:显存不足,KV Cache 满。
解决方案:
--max-num-seqs--max-model-len案例二:计算瓶颈
现象:
bash
nvidia-smi dmon -s mu # gpu sm mem # Idx % % 0 95 65 0 96 68 显存占用不高(65-68%),但 GPU 利用率持续 > 94%。
判断:计算能力不足,GPU 满负荷运行。
解决方案:
案例三:CPU 瓶颈
现象:
bash
top -b -n 1 | grep python 12345 root 20 0 52.3g 12.5g 1.2g S 780.0 15.3 45:23.45 python CPU 利用率 780%(多核),GPU 利用率只有 40%。
判断:tokenize/decode 成为瓶颈。
解决方案:
案例四:I/O 瓶颈
现象:
bash
time docker start real 2m15.432s iostat -x 1 Device %util nvme0n1 98.5 判断:模型加载受磁盘 I/O 限制。
解决方案:
bash
#!/bin/bash echo "=== GPU Status ===" nvidia-smi --query-gpu=index,name,memory.used,memory.total,utilization.gpu,utilization.memory,temperature.gpu,power.draw --format=csv echo "" echo "=== vLLM Metrics ===" curl -s http://localhost:8000/metrics | grep -E "vllm_gpu_cache_usage|vllm_num_requests" echo "" echo "=== CPU Usage ===" ps aux | grep python | grep vllm | awk '{print "CPU:", $3"%", "MEM:", $4"%"}' echo "" echo "=== Disk I/O ===" iostat -x | grep nvme0n1 运行:
bash
chmod +x monitor_inference.sh ./monitor_inference.sh
全部0条评论
快来发表一下你的评论吧 !