跳转至

模型服务化

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应用的全生命周期管理

评论 #