模型服务化
1. 服务化模式
1.1 REST API
最常见的模型服务接口:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class ChatRequest(BaseModel):
messages: list[dict]
model: str = "gpt-4"
temperature: float = 0.7
max_tokens: int = 1024
class ChatResponse(BaseModel):
id: str
choices: list[dict]
usage: dict
@app.post("/v1/chat/completions")
async def chat_completion(request: ChatRequest):
# 模型推理
response = await model.generate(
messages=request.messages,
temperature=request.temperature,
max_tokens=request.max_tokens,
)
return ChatResponse(
id=generate_id(),
choices=[{"message": {"role": "assistant", "content": response}}],
usage={"prompt_tokens": ..., "completion_tokens": ..., "total_tokens": ...}
)
特点:
- 简单、通用、易于调试
- 基于HTTP/HTTPS,广泛兼容
- 适合大多数应用场景
- OpenAI兼容API格式已成为事实标准
1.2 gRPC
高性能RPC框架,适合内部服务通信:
// inference.proto
service InferenceService {
rpc Predict (PredictRequest) returns (PredictResponse);
rpc StreamPredict (PredictRequest) returns (stream PredictResponse);
}
message PredictRequest {
string model_name = 1;
repeated Message messages = 2;
float temperature = 3;
int32 max_tokens = 4;
}
message PredictResponse {
string text = 1;
TokenUsage usage = 2;
}
特点:
- 比REST更高性能(Protocol Buffers序列化)
- 原生支持流式传输
- 强类型接口定义
- 适合微服务间通信
1.3 流式传输 (Streaming)
LLM生成的文本通过SSE(Server-Sent Events)逐步返回:
from fastapi.responses import StreamingResponse
@app.post("/v1/chat/completions/stream")
async def chat_completion_stream(request: ChatRequest):
async def generate():
async for token in model.generate_stream(
messages=request.messages,
temperature=request.temperature,
):
chunk = {
"choices": [{"delta": {"content": token}}]
}
yield f"data: {json.dumps(chunk)}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream"
)
流式传输的优势:
- 用户体验: 首个token的响应时间(TTFT)更短
- 内存效率: 无需等待完整响应
- 超时处理: 减少长文本生成的超时风险
2. 推理服务框架
2.1 Triton Inference Server
NVIDIA推出的高性能推理服务器:
特点:
- 支持多种框架(PyTorch, TensorFlow, ONNX, TensorRT)
- 动态批处理
- 模型并发执行
- GPU共享和管理
- 内置性能监控
适用场景:
- 多模型服务
- 高吞吐量需求
- GPU资源优化
- 企业级部署
模型仓库结构:
model_repository/
├── llm_model/
│ ├── config.pbtxt
│ ├── 1/
│ │ └── model.plan
│ └── 2/
│ └── model.plan
2.2 vLLM
专为LLM推理优化的高性能服务框架:
from vllm import LLM, SamplingParams
# 加载模型
llm = LLM(
model="meta-llama/Llama-3-8B-Instruct",
tensor_parallel_size=2, # GPU并行数
gpu_memory_utilization=0.9, # GPU内存利用率
max_model_len=8192, # 最大序列长度
)
# 推理
sampling_params = SamplingParams(
temperature=0.7,
top_p=0.9,
max_tokens=1024,
)
outputs = llm.generate(["What is AI?"], sampling_params)
vLLM关键技术:
- PagedAttention: 将KV-Cache分页管理,减少内存浪费
- Continuous Batching: 动态批处理,提高GPU利用率
- Tensor Parallelism: 多GPU并行推理
- Speculative Decoding: 推测性解码加速
启动OpenAI兼容服务:
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Llama-3-8B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--tensor-parallel-size 2
2.3 TGI (Text Generation Inference)
Hugging Face推出的文本生成推理框架:
# Docker部署
docker run --gpus all \
-p 8080:80 \
-v $PWD/data:/data \
ghcr.io/huggingface/text-generation-inference:latest \
--model-id meta-llama/Llama-3-8B-Instruct \
--quantize gptq \
--max-input-length 4096 \
--max-total-tokens 8192
特点:
- Flash Attention支持
- 量化推理(GPTQ、AWQ、EETQ)
- 水印(Watermarking)
- Token流式传输
- 生产级Rust实现
2.4 框架对比
| 特性 | vLLM | TGI | Triton |
|---|---|---|---|
| 专注 | LLM推理 | 文本生成 | 通用推理 |
| 性能 | 极高 | 高 | 高 |
| 易用性 | 高 | 高 | 中 |
| 多模型 | 有限 | 有限 | 优秀 |
| 量化支持 | AWQ, GPTQ, FP8 | GPTQ, AWQ | TensorRT |
| 社区 | 活跃 | 活跃 | NVIDIA维护 |
3. API网关
3.1 速率限制 (Rate Limiting)
from fastapi import FastAPI, HTTPException
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app = FastAPI()
@app.post("/v1/chat/completions")
@limiter.limit("60/minute") # 每分钟60次请求
async def chat_completion(request: ChatRequest):
...
限流策略:
- 固定窗口: 每分钟N次请求
- 滑动窗口: 更平滑的限流
- 令牌桶: 允许突发流量
- 按用户/API Key: 不同用户不同限额
3.2 认证与授权 (Auth)
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
@app.post("/v1/chat/completions")
async def chat_completion(
request: ChatRequest,
credentials: HTTPAuthorizationCredentials = Depends(security)
):
# 验证API Key
if not verify_api_key(credentials.credentials):
raise HTTPException(status_code=401, detail="Invalid API key")
# 检查权限
user = get_user_by_key(credentials.credentials)
if not user.has_permission("chat"):
raise HTTPException(status_code=403, detail="Insufficient permissions")
...
3.3 请求日志与监控
import time
import logging
@app.middleware("http")
async def log_requests(request, call_next):
start_time = time.time()
response = await call_next(request)
duration = time.time() - start_time
logging.info(f"{request.method} {request.url.path} "
f"status={response.status_code} "
f"duration={duration:.3f}s")
# 发送到监控系统
metrics.record_request(
path=request.url.path,
status=response.status_code,
duration=duration,
)
return response
4. 负载均衡
4.1 策略选择
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 轮询 (Round Robin) | 依次分配请求 | 均匀负载 |
| 加权轮询 | 按GPU性能分配 | 异构GPU集群 |
| 最少连接 | 分配给连接最少的实例 | 请求时长差异大 |
| 一致性哈希 | 相同用户分配到相同实例 | 需要会话亲和性 |
| 最快响应 | 分配给响应最快的实例 | 延迟敏感 |
4.2 健康检查
@app.get("/health")
async def health_check():
return {
"status": "healthy",
"gpu_memory_used": get_gpu_memory_usage(),
"active_requests": get_active_request_count(),
"model_loaded": model.is_loaded(),
}
@app.get("/ready")
async def readiness_check():
if not model.is_loaded():
raise HTTPException(status_code=503, detail="Model not ready")
return {"status": "ready"}
5. 自动扩缩 (Auto-scaling)
5.1 扩缩指标
- QPS: 每秒查询数
- GPU利用率: GPU计算资源使用率
- 队列长度: 等待处理的请求数
- 响应延迟: P95/P99延迟
5.2 Kubernetes HPA配置
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: llm-inference
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: gpu_utilization
target:
type: AverageValue
averageValue: "80"
- type: Pods
pods:
metric:
name: request_queue_length
target:
type: AverageValue
averageValue: "10"
5.3 冷启动优化
- 模型预加载: 启动时预加载模型到GPU
- 最小副本数: 保持最少2个实例运行
- 预热请求: 启动后发送预热请求
- 模型缓存: 使用共享存储缓存模型权重
6. 批处理策略
6.1 静态批处理 (Static Batching)
收集固定数量的请求 → 一起处理 → 一起返回
缺点:必须等所有请求到达才处理
6.2 动态批处理 (Dynamic Batching)
设置最大等待时间 → 在时间窗口内收集请求 → 批量处理
优点:平衡延迟和吞吐量
6.3 连续批处理 (Continuous Batching)
请求A: [生成中...] [完成] →
请求B: [生成中...........] [完成] →
请求C: [生成中......] [完成] →
请求D: [生成中...] [完成] →
新请求可以在前面的请求完成时立即加入批次
vLLM的连续批处理:
- 一旦有请求完成,立即加入新请求
- 最大化GPU利用率
- 比静态批处理吞吐量提升2-4倍
7. 服务化架构
graph TD
Client[客户端] --> LB[负载均衡器]
LB --> GW[API网关]
GW --> Auth[认证授权]
GW --> RL[速率限制]
GW --> Log[日志监控]
GW --> Router[请求路由]
Router --> S1[推理服务实例1<br/>GPU: A100]
Router --> S2[推理服务实例2<br/>GPU: A100]
Router --> S3[推理服务实例3<br/>GPU: H100]
S1 --> Cache[KV-Cache<br/>Redis]
S2 --> Cache
S3 --> Cache
Router --> Queue[请求队列<br/>Kafka/Redis]
Queue --> S1
Queue --> S2
Queue --> S3
Monitor[监控系统<br/>Prometheus + Grafana] --> S1
Monitor --> S2
Monitor --> S3
Monitor --> GW
HPA[自动扩缩<br/>K8s HPA] --> S1
HPA --> S2
HPA --> S3
8. 实践清单
- [ ] 选择推理框架(vLLM/TGI/Triton)
- [ ] 实现OpenAI兼容API
- [ ] 配置流式传输
- [ ] 部署API网关(认证、限流)
- [ ] 设置负载均衡和健康检查
- [ ] 配置自动扩缩
- [ ] 实现连续批处理
- [ ] 建立监控和告警
参考资料
- vLLM Documentation
- NVIDIA Triton Inference Server Documentation
- Hugging Face Text Generation Inference Documentation
- LLMOps综述 — LLM应用的全生命周期管理