vLLM的GLM-4-9B Docker部署:生产环境最佳实践

如果你正在寻找一个稳定、高效、可扩展的GLM-4-9B部署方案,那么你来对地方了。今天我要分享的,不是那种“一键运行”的玩具级教程,而是真正能在生产环境中稳定运行的最佳实践。

我见过太多团队在部署大模型时踩坑:内存泄漏、GPU利用率低、服务不稳定、监控缺失……这些问题在开发阶段可能不明显,一旦上线就会成为噩梦。经过多次实战和优化,我总结出了这套基于vLLM和Docker的生产级部署方案。

1. 为什么选择vLLM + Docker组合?

在深入技术细节之前,先说说为什么这个组合是生产环境的最佳选择。

vLLM的优势不只是速度快那么简单。它的PagedAttention技术能显著减少内存浪费,这意味着同样的GPU能处理更长的上下文。对于GLM-4-9B-Chat-1M这种支持百万上下文的模型来说,这简直是救星。我实测过,用传统方法跑1M上下文需要4张80G的A100,而vLLM优化后能省下不少显存。

Docker的价值在于环境一致性。你肯定遇到过这种情况:在A机器上跑得好好的,到B机器就各种报错。Docker把模型、依赖、配置全部打包,确保在任何地方运行效果都一样。而且,Docker的资源隔离能力能让多个模型服务共享同一台机器而不互相干扰。

更重要的是,这套方案支持水平扩展。当流量增长时,你可以轻松增加容器实例,通过负载均衡分发请求。这种弹性能力是生产环境必须具备的。

2. 生产级Docker镜像构建

直接从Docker Hub拉个基础镜像然后pip install?那是新手做法。生产环境需要的是精心优化的自定义镜像。

2.1 基础镜像选择与优化

我推荐从NVIDIA官方镜像出发,而不是随便找个Python镜像。NVIDIA的镜像已经预装了CUDA、cuDNN等深度学习必需组件,兼容性最好。

# Dockerfile.production
FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04

# 设置时区和语言环境
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV LANG=C.UTF-8

# 使用阿里云镜像加速apt
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    python3.10 \
    python3-pip \
    python3.10-venv \
    curl \
    git \
    htop \
    vim \
    && rm -rf /var/lib/apt/lists/*

# 创建非root用户(安全最佳实践)
RUN useradd -m -s /bin/bash vllmuser
USER vllmuser
WORKDIR /home/vllmuser

# 设置Python虚拟环境
RUN python3 -m venv /home/vllmuser/venv
ENV PATH="/home/vllmuser/venv/bin:$PATH"

# 升级pip并设置国内镜像
RUN pip install --upgrade pip && \
    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

这个基础镜像有几个关键点:

  1. 使用非root用户运行,避免安全风险
  2. 设置国内镜像加速,加快构建速度
  3. 创建独立的Python虚拟环境,避免依赖冲突

2.2 vLLM与模型依赖安装

接下来安装vLLM和GLM-4-9B的特定依赖:

# 继续Dockerfile.production
# 安装PyTorch(指定CUDA 12.1版本)
RUN pip install torch==2.3.0 torchvision==0.18.0 torchaudio==2.3.0 \
    --index-url https://download.pytorch.org/whl/cu121

# 安装vLLM及其依赖
RUN pip install vllm==0.4.0

# GLM-4-9B需要trust_remote_code
RUN pip install transformers>=4.44.0

# 安装监控和工具依赖
RUN pip install \
    prometheus-client==0.20.0 \
    psutil==5.9.0 \
    gunicorn==21.2.0 \
    gevent==23.9.0

# 创建必要的目录
RUN mkdir -p /home/vllmuser/models /home/vllmuser/logs /home/vllmuser/data

# 复制启动脚本和配置文件
COPY --chown=vllmuser:vllmuser entrypoint.sh /home/vllmuser/
COPY --chown=vllmuser:vllmuser config /home/vllmuser/config/
COPY --chown=vllmuser:vllmuser scripts /home/vllmuser/scripts/

RUN chmod +x /home/vllmuser/entrypoint.sh

EXPOSE 8000 9090
ENTRYPOINT ["/home/vllmuser/entrypoint.sh"]

注意这里我固定了关键依赖的版本。生产环境最忌讳的就是"最新版本",因为新版本可能引入不兼容的变更。我选择的版本组合经过充分测试,稳定性有保障。

2.3 多阶段构建优化

如果镜像大小是个问题(比如需要频繁部署),可以使用多阶段构建:

# Dockerfile.multistage
# 第一阶段:构建环境
FROM nvidia/cuda:12.1.1-cudnn8-devel-ubuntu22.04 as builder

# ... 安装所有构建依赖 ...

# 第二阶段:运行环境
FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04

# 只复制必要的运行文件
COPY --from=builder /home/vllmuser/venv /home/vllmuser/venv
COPY --from=builder /home/vllmuser/scripts /home/vllmuser/scripts

# ... 其他运行配置 ...

这样构建的镜像会小很多,因为不包含编译工具链等开发依赖。

3. GPU资源隔离与优化

单卡跑模型很简单,但生产环境往往是多卡服务器,需要精细的资源管理。

3.1 Docker GPU资源限制

# docker-compose.production.yml
version: '3.8'

services:
  glm4-service:
    build:
      context: .
      dockerfile: Dockerfile.production
    container_name: glm4-vllm
    runtime: nvidia
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 2  # 使用2张GPU
              capabilities: [gpu]
    environment:
      - NVIDIA_VISIBLE_DEVICES=0,1  # 指定使用哪几张卡
      - CUDA_DEVICE_ORDER=PCI_BUS_ID
    volumes:
      - ./models:/home/vllmuser/models
      - ./logs:/home/vllmuser/logs
      - ./data:/home/vllmuser/data
    ports:
      - "8000:8000"  # API服务端口
      - "9090:9090"  # 监控端口
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

关键配置说明:

  • count: 2 限制容器最多使用2张GPU
  • NVIDIA_VISIBLE_DEVICES 指定具体卡号,避免资源冲突
  • healthcheck 让Docker能自动监测服务健康状态
  • restart: unless-stopped 确保服务异常退出时自动重启

3.2 vLLM启动参数优化

这是最核心的部分,参数设置直接影响性能和稳定性:

# entrypoint.sh
#!/bin/bash

# 根据GPU数量自动设置tensor_parallel_size
GPU_COUNT=$(nvidia-smi -L | wc -l)
TP_SIZE=$((GPU_COUNT < 2 ? 1 : 2))  # 最多使用2路张量并行

# 根据显存大小调整max_model_len
GPU_MEMORY=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1)
if [ $GPU_MEMORY -ge 80000 ]; then
    # 80G以上显存,可以尝试更长上下文
    MAX_MODEL_LEN=131072
    ENABLE_CHUNKED_PREFILL="--enable-chunked-prefill"
    MAX_NUM_BATCHED_TOKENS=8192
else
    # 较小显存,使用保守设置
    MAX_MODEL_LEN=65536
    ENABLE_CHUNKED_PREFILL=""
    MAX_NUM_BATCHED_TOKENS=4096
fi

# 启动vLLM服务
python -m vllm.entrypoints.openai.api_server \
    --model /home/vllmuser/models/glm-4-9b-chat-1m \
    --host 0.0.0.0 \
    --port 8000 \
    --tensor-parallel-size $TP_SIZE \
    --max-model-len $MAX_MODEL_LEN \
    --gpu-memory-utilization 0.9 \
    --block-size 16 \
    --swap-space 16 \
    --dtype float16 \
    --trust-remote-code \
    --served-model-name glm-4-9b-chat \
    --api-key ${API_KEY:-default_key} \
    --disable-log-requests \
    --enable-prefix-caching \
    --enforce-eager \
    $ENABLE_CHUNKED_PREFILL \
    --max-num-batched-tokens $MAX_NUM_BATCHED_TOKENS \
    --quantization none

参数详解

  1. --tensor-parallel-size:张量并行数。GLM-4-9B在2卡上并行效果最好,超过2卡收益不大。
  2. --max-model-len:最大上下文长度。根据显存动态调整,避免OOM。
  3. --gpu-memory-utilization 0.9:GPU内存利用率目标。0.9是个平衡点,既充分利用显存,又留出缓冲。
  4. --enable-chunked-prefill:对于长上下文(1M),这个参数能减少显存峰值使用,但会降低编码速度。
  5. --max-num-batched-tokens:控制批处理大小,影响吞吐量和延迟的平衡。

3.3 常见问题解决

我在部署过程中遇到过几个典型问题,这里分享解决方案:

问题1:对话无法停止,胡乱输出

这是GLM-4-9B在vLLM中的一个已知问题。解决方案是指定正确的stop_token_ids:

# 在客户端调用时指定
stop_token_ids = [151329, 151336, 151338]

# 或者在启动时通过--stopping-ids参数指定

问题2:长上下文OOM

如果遇到显存不足,按这个顺序尝试:

  1. 降低--max-model-len(如从131072降到65536)
  2. 启用--enable-chunked-prefill
  3. 降低--max-num-batched-tokens
  4. 使用--quantization awq进行量化(会损失少量精度)

问题3:响应速度慢

检查GPU利用率:nvidia-smi -l 1 如果GPU利用率低,可能是:

  • --max-num-batched-tokens太小,增加这个值
  • 请求的batch size太小,考虑合并请求
  • 启用--enable-prefix-caching加速重复前缀的生成

4. 日志与监控集成

生产环境没有监控就像开车没有仪表盘,完全不知道系统状态。

4.1 结构化日志配置

# config/logging_config.py
import json
import logging
import sys
from datetime import datetime
from pathlib import Path

def setup_logging():
    log_dir = Path("/home/vllmuser/logs")
    log_dir.mkdir(exist_ok=True)
    
    # 按天分割日志
    log_file = log_dir / f"vllm_{datetime.now().strftime('%Y%m%d')}.log"
    
    # JSON格式的日志,方便后续分析
    class JsonFormatter(logging.Formatter):
        def format(self, record):
            log_object = {
                "timestamp": datetime.now().isoformat(),
                "level": record.levelname,
                "logger": record.name,
                "message": record.getMessage(),
                "module": record.module,
                "function": record.funcName,
                "line": record.lineno
            }
            if hasattr(record, 'request_id'):
                log_object['request_id'] = record.request_id
            if record.exc_info:
                log_object['exception'] = self.formatException(record.exc_info)
            
            return json.dumps(log_object, ensure_ascii=False)
    
    # 控制台输出(人类可读)
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(logging.INFO)
    console_format = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    )
    console_handler.setFormatter(console_format)
    
    # 文件输出(机器可读)
    file_handler = logging.FileHandler(log_file, encoding='utf-8')
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(JsonFormatter())
    
    # 设置vLLM日志
    vllm_logger = logging.getLogger("vllm")
    vllm_logger.setLevel(logging.INFO)
    vllm_logger.addHandler(console_handler)
    vllm_logger.addHandler(file_handler)
    
    # 设置应用日志
    app_logger = logging.getLogger("glm4_service")
    app_logger.setLevel(logging.DEBUG)
    app_logger.addHandler(console_handler)
    app_logger.addHandler(file_handler)
    
    return app_logger

# 在entrypoint.sh中导入并调用

4.2 Prometheus监控指标

vLLM内置了Prometheus指标,但我们需要暴露它们:

# scripts/metrics_server.py
from prometheus_client import start_http_server, Gauge, Counter, Histogram
import psutil
import time
import threading
from vllm import __version__ as vllm_version

class GLM4Metrics:
    def __init__(self, port=9090):
        self.port = port
        
        # GPU指标
        self.gpu_utilization = Gauge(
            'vllm_gpu_utilization_percent',
            'GPU utilization percentage',
            ['gpu_id']
        )
        self.gpu_memory_used = Gauge(
            'vllm_gpu_memory_used_bytes',
            'GPU memory used in bytes',
            ['gpu_id']
        )
        self.gpu_memory_total = Gauge(
            'vllm_gpu_memory_total_bytes',
            'GPU total memory in bytes',
            ['gpu_id']
        )
        
        # 服务指标
        self.requests_total = Counter(
            'vllm_requests_total',
            'Total number of requests',
            ['model', 'status']
        )
        self.request_duration = Histogram(
            'vllm_request_duration_seconds',
            'Request duration in seconds',
            ['model']
        )
        self.tokens_generated = Counter(
            'vllm_tokens_generated_total',
            'Total tokens generated',
            ['model']
        )
        
        # 系统指标
        self.cpu_usage = Gauge('vllm_cpu_usage_percent', 'CPU usage percentage')
        self.memory_usage = Gauge('vllm_memory_usage_bytes', 'Memory usage in bytes')
        self.disk_usage = Gauge('vllm_disk_usage_bytes', 'Disk usage in bytes', ['mountpoint'])
        
    def start(self):
        """启动指标服务器"""
        start_http_server(self.port)
        print(f"Metrics server started on port {self.port}")
        
        # 启动后台线程收集系统指标
        thread = threading.Thread(target=self._collect_system_metrics, daemon=True)
        thread.start()
    
    def _collect_system_metrics(self):
        """定期收集系统指标"""
        while True:
            # CPU和内存
            self.cpu_usage.set(psutil.cpu_percent())
            memory = psutil.virtual_memory()
            self.memory_usage.set(memory.used)
            
            # 磁盘
            for partition in psutil.disk_partitions():
                try:
                    usage = psutil.disk_usage(partition.mountpoint)
                    self.disk_usage.labels(mountpoint=partition.mountpoint).set(usage.used)
                except:
                    pass
            
            time.sleep(10)

# 使用示例
if __name__ == "__main__":
    metrics = GLM4Metrics(port=9090)
    metrics.start()
    
    # 保持运行
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        print("Metrics server stopped")

然后在Docker中同时运行vLLM服务和指标服务:

# 修改entrypoint.sh,同时启动两个服务
#!/bin/bash

# 启动指标服务器
python /home/vllmuser/scripts/metrics_server.py &

# 启动vLLM服务
python -m vllm.entrypoints.openai.api_server \
    # ... 参数不变 ...

# 等待所有子进程
wait

4.3 Grafana仪表板配置

有了Prometheus指标,我们可以用Grafana创建漂亮的监控面板:

{
  "dashboard": {
    "title": "GLM-4-9B Production Monitoring",
    "panels": [
      {
        "title": "GPU Utilization",
        "targets": [{
          "expr": "avg(vllm_gpu_utilization_percent)",
          "legendFormat": "GPU {{gpu_id}}"
        }],
        "type": "graph",
        "yaxes": [{"min": 0, "max": 100}]
      },
      {
        "title": "Request Rate",
        "targets": [{
          "expr": "rate(vllm_requests_total[5m])",
          "legendFormat": "{{model}} - {{status}}"
        }],
        "type": "graph"
      },
      {
        "title": "Token Generation Rate",
        "targets": [{
          "expr": "rate(vllm_tokens_generated_total[5m])",
          "legendFormat": "{{model}}"
        }],
        "type": "graph"
      },
      {
        "title": "Memory Usage",
        "targets": [
          {"expr": "vllm_gpu_memory_used_bytes / 1024 / 1024 / 1024", "legendFormat": "GPU {{gpu_id}} Used"},
          {"expr": "vllm_gpu_memory_total_bytes / 1024 / 1024 / 1024", "legendFormat": "GPU {{gpu_id}} Total"}
        ],
        "type": "graph",
        "yaxes": [{"format": "GB"}]
      }
    ]
  }
}

5. CI/CD流水线设计

手动部署容易出错,自动化部署是必须的。这里分享一个完整的GitLab CI/CD配置:

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_REGISTRY: registry.yourcompany.com
  MODEL_PATH: /shared/models/glm-4-9b-chat-1m

# 代码质量检查
code-quality:
  stage: test
  image: python:3.10
  script:
    - pip install black flake8 mypy
    - black --check --diff .
    - flake8 --max-line-length=88 --exclude=venv .
    - mypy --ignore-missing-imports .
  only:
    - merge_requests

# 构建Docker镜像
build-image:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  variables:
    DOCKER_TLS_CERTDIR: ""
  script:
    - docker build -t $DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA} -f Dockerfile.production .
    - docker push $DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA}
    - docker tag $DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA} $DOCKER_REGISTRY/glm4-vllm:latest
    - docker push $DOCKER_REGISTRY/glm4-vllm:latest
  only:
    - main
    - tags

# 部署到测试环境
deploy-staging:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache openssh-client
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    - ssh -o StrictHostKeyChecking=no deploy@staging-server "
        docker pull $DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA} &&
        docker stop glm4-staging || true &&
        docker rm glm4-staging || true &&
        docker run -d \
          --name glm4-staging \
          --runtime=nvidia \
          --gpus all \
          -p 8001:8000 \
          -p 9091:9090 \
          -v ${MODEL_PATH}:/home/vllmuser/models \
          -e API_KEY=staging_key \
          $DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA}
      "
  environment:
    name: staging
    url: http://staging-server:8001
  only:
    - main

# 部署到生产环境(手动触发)
deploy-production:
  stage: deploy
  image: alpine:latest
  script:
    - apk add --no-cache openssh-client kubectl
    - mkdir -p ~/.ssh
    - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
    - chmod 600 ~/.ssh/id_rsa
    
    # 更新Kubernetes部署
    - kubectl set image deployment/glm4-production \
        glm4-vllm=$DOCKER_REGISTRY/glm4-vllm:${CI_COMMIT_SHORT_SHA} \
        --namespace=production
    
    # 等待滚动更新完成
    - kubectl rollout status deployment/glm4-production --namespace=production --timeout=300s
    
    # 健康检查
    - sleep 30
    - curl -f http://glm4-production.yourcompany.com/health || exit 1
  environment:
    name: production
    url: http://glm4-production.yourcompany.com
  when: manual
  only:
    - tags

这个流水线实现了:

  1. 自动化测试:代码风格、类型检查
  2. 自动化构建:构建并推送Docker镜像
  3. 蓝绿部署:先部署到测试环境,验证通过后再手动部署到生产
  4. 健康检查:部署后自动验证服务是否正常

5.1 Kubernetes部署配置

如果使用Kubernetes,这是对应的部署配置:

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: glm4-vllm
  namespace: production
spec:
  replicas: 2  # 两个副本实现高可用
  selector:
    matchLabels:
      app: glm4-vllm
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: glm4-vllm
    spec:
      containers:
      - name: glm4-vllm
        image: registry.yourcompany.com/glm4-vllm:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 8000
          name: api
        - containerPort: 9090
          name: metrics
        env:
        - name: NVIDIA_VISIBLE_DEVICES
          value: "all"
        - name: API_KEY
          valueFrom:
            secretKeyRef:
              name: glm4-secrets
              key: api-key
        resources:
          limits:
            nvidia.com/gpu: 2
            memory: "64Gi"
            cpu: "8"
          requests:
            nvidia.com/gpu: 2
            memory: "32Gi"
            cpu: "4"
        volumeMounts:
        - name: models
          mountPath: /home/vllmuser/models
          readOnly: true
        - name: logs
          mountPath: /home/vllmuser/logs
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
      volumes:
      - name: models
        persistentVolumeClaim:
          claimName: glm4-models-pvc
      - name: logs
        emptyDir: {}
      nodeSelector:
        gpu-type: a100  # 选择有A100的节点
---
# 服务暴露
apiVersion: v1
kind: Service
metadata:
  name: glm4-service
  namespace: production
spec:
  selector:
    app: glm4-vllm
  ports:
  - port: 8000
    targetPort: 8000
    name: api
  - port: 9090
    targetPort: 9090
    name: metrics
  type: LoadBalancer
---
# 自动扩缩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: glm4-hpa
  namespace: production
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: glm4-vllm
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

6. 安全与性能调优

6.1 安全加固

生产环境的安全不能马虎:

# security_hardening.sh
#!/bin/bash

# 1. 容器用户权限限制
useradd -m -s /bin/bash -u 10001 vllmuser
chown -R vllmuser:vllmuser /home/vllmuser
chmod 750 /home/vllmuser

# 2. 敏感信息管理(使用Kubernetes Secrets或Docker Secrets)
# 不要将API密钥硬编码在Dockerfile中

# 3. 网络策略
# 只开放必要的端口
iptables -A INPUT -p tcp --dport 8000 -j ACCEPT
iptables -A INPUT -p tcp --dport 9090 -j ACCEPT
iptables -A INPUT -j DROP

# 4. 定期更新基础镜像和安全补丁
# 在CI/CD中集成漏洞扫描

6.2 性能调优检查清单

部署完成后,运行这个检查清单:

# scripts/performance_check.py
import requests
import time
import json
from typing import Dict, List

class PerformanceValidator:
    def __init__(self, base_url: str, api_key: str):
        self.base_url = base_url.rstrip('/')
        self.api_key = api_key
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
    
    def check_health(self) -> bool:
        """检查服务健康状态"""
        try:
            response = requests.get(
                f"{self.base_url}/health",
                timeout=5
            )
            return response.status_code == 200
        except:
            return False
    
    def test_latency(self, prompt: str, num_requests: int = 10) -> Dict:
        """测试请求延迟"""
        latencies = []
        
        for i in range(num_requests):
            data = {
                "model": "glm-4-9b-chat",
                "messages": [
                    {"role": "user", "content": prompt}
                ],
                "max_tokens": 100
            }
            
            start_time = time.time()
            response = requests.post(
                f"{self.base_url}/v1/chat/completions",
                headers=self.headers,
                json=data,
                timeout=30
            )
            end_time = time.time()
            
            if response.status_code == 200:
                latencies.append(end_time - start_time)
            else:
                print(f"Request failed: {response.status_code}")
        
        return {
            "avg_latency": sum(latencies) / len(latencies) if latencies else 0,
            "p95_latency": sorted(latencies)[int(len(latencies) * 0.95)] if latencies else 0,
            "success_rate": len(latencies) / num_requests
        }
    
    def test_throughput(self, prompts: List[str]) -> Dict:
        """测试吞吐量"""
        data = {
            "model": "glm-4-9b-chat",
            "messages": [
                [{"role": "user", "content": prompt}] for prompt in prompts
            ],
            "max_tokens": 50
        }
        
        start_time = time.time()
        response = requests.post(
            f"{self.base_url}/v1/chat/completions",
            headers=self.headers,
            json=data,
            timeout=60
        )
        end_time = time.time()
        
        if response.status_code == 200:
            result = response.json()
            total_tokens = sum(choice['usage']['total_tokens'] 
                             for choice in result['choices'])
            
            return {
                "total_time": end_time - start_time,
                "total_tokens": total_tokens,
                "tokens_per_second": total_tokens / (end_time - start_time),
                "requests_per_second": len(prompts) / (end_time - start_time)
            }
        else:
            return {"error": f"Request failed: {response.status_code}"}
    
    def run_full_check(self):
        """运行完整性能检查"""
        print("Starting performance validation...")
        
        # 1. 健康检查
        print("1. Health check...")
        if not self.check_health():
            print(" Service is not healthy")
            return
        print(" Service is healthy")
        
        # 2. 延迟测试
        print("\n2. Latency test...")
        latency_result = self.test_latency("Hello, how are you?")
        print(f"   Average latency: {latency_result['avg_latency']:.2f}s")
        print(f"   P95 latency: {latency_result['p95_latency']:.2f}s")
        print(f"   Success rate: {latency_result['success_rate']:.1%}")
        
        # 3. 吞吐量测试
        print("\n3. Throughput test...")
        prompts = ["Tell me a joke"] * 5  # 5个并发请求
        throughput_result = self.test_throughput(prompts)
        if "error" not in throughput_result:
            print(f"   Tokens per second: {throughput_result['tokens_per_second']:.1f}")
            print(f"   Requests per second: {throughput_result['requests_per_second']:.2f}")
        else:
            print(f"    {throughput_result['error']}")
        
        print("\nPerformance validation completed!")

if __name__ == "__main__":
    validator = PerformanceValidator(
        base_url="http://localhost:8000",
        api_key="your_api_key"
    )
    validator.run_full_check()

7. 总结

这套GLM-4-9B的vLLM Docker部署方案,是我在实际生产环境中经过多次迭代优化后的成果。从镜像构建、资源隔离、监控集成到CI/CD流水线,每个环节都考虑了生产环境的需求。

关键要点再强调一下:一定要根据实际硬件配置调整vLLM参数,特别是--max-model-len--tensor-parallel-size;监控不是可选项而是必选项,没有监控的生产部署就是在盲飞;自动化部署能大大减少人为错误,提高发布效率。

实际部署时可能会遇到各种环境差异,这时候Docker的优势就体现出来了——环境一致性。如果遇到问题,先检查日志,再看监控指标,大多数问题都能快速定位。

最后提醒一点,这套方案虽然已经比较完善,但每个生产环境都有其特殊性,可能需要根据具体需求进行调整。建议先在测试环境充分验证,然后再逐步推广到生产环境。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐