Skip to content

필사 모드: Ray Serve 模型服务平台构建指南 — 自动扩缩容、多模型、生产部署

中文
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
Ray Serve 模型服务平台

引言

在生产环境中服务 ML 模型,与训练是完全不同的工程领域。单一模型的服务用 Flask 或 FastAPI 也能做到,但在需要同时服务多个模型、根据流量自动扩缩容、高效管理 GPU 资源,还要处理故障恢复的生产环境中,专门的服务框架是必不可少的。

Ray Serve 是构建在 Ray 之上的可扩展模型服务库,不绑定特定框架,PyTorch、TensorFlow、Scikit-Learn、XGBoost 等任何模型都能服务。尤其凭借多模型合成、可编程 API、分布式服务这三大核心优势,能用 Python 代码自然地组合出复杂的推理流水线,这一点使它与其他服务框架区分开来。

本文将结合实战代码,涵盖从 Ray Serve 的架构到 LLM 服务、自动扩缩容、Kubernetes 部署、运维故障排查等生产环境所需的全部内容。

Ray Serve 架构与核心概念

架构概览

Ray Serve 是运行在 Ray 集群之上、基于 Actor 的服务框架。整体结构如下。

Client (HTTP/gRPC)
        |
        v
+-------------------+
|   HTTP Proxy      |  (Ingress、路由、负载均衡)
+-------------------+
        |
        v
+-------------------+     +-------------------+
|  Deployment A     |     |  Deployment B     |
|  - Replica 1      |     |  - Replica 1      |
|  - Replica 2      |     |  - Replica 2      |
|  - Replica 3      |     |  - Replica 3      |
+-------------------+     +-------------------+
        |                         |
        v                         v
+-------------------------------------------+
|          Ray Cluster (分布式运行时)          |
|  - Head Node (Serve Controller)            |
|  - Worker Node 1 (GPU)                     |
|  - Worker Node 2 (GPU)                     |
+-------------------------------------------+

三个核心概念

Deployment(部署单元):封装模型或业务逻辑的服务基本单位。每个 Deployment 都可以独立扩缩容、更新、回滚。通过 @serve.deployment 装饰器定义。

Replica(副本):Deployment 的运行实例,以 Ray Actor 的形式实现。一个 Deployment 可以拥有多个 Replica 来做水平扩展,每个 Replica 都运行在独立的进程中。GPU 分配、CPU 核心数等资源可以逐个单独设置。

DeploymentHandle(部署句柄):在 Python 代码中调用另一个 Deployment 时使用的异步句柄。可以像普通函数调用一样使用,Ray Serve 会在内部处理负载均衡和序列化。这是多模型合成的核心机制。

import ray
from ray import serve
from transformers import pipeline

@serve.deployment(
    num_replicas=2,
    ray_actor_options={"num_gpus": 1},
)
class SentimentModel:
    def __init__(self):
        self.model = pipeline(
            "sentiment-analysis",
            model="distilbert-base-uncased-finetuned-sst-2-english",
            device=0,
        )

    async def __call__(self, request):
        data = await request.json()
        result = self.model(data["text"])
        return {"prediction": result}

@serve.deployment(num_replicas=1)
class Router:
    def __init__(self, sentiment_handle):
        self.sentiment = sentiment_handle

    async def __call__(self, request):
        # 通过 DeploymentHandle 进行内部调用
        result = await self.sentiment.remote(request)
        return result

sentiment_app = SentimentModel.bind()
router_app = Router.bind(sentiment_app)
serve.run(router_app, route_prefix="/predict")

Ray Serve 与 vLLM、TorchServe、Triton 对比

在选择模型服务框架时,准确理解每种工具的优势与局限非常重要。

项目Ray ServevLLMTorchServeTriton Inference Server
主要用途通用模型服务、多模型流水线LLM 专用高性能推理PyTorch 模型服务通用 GPU 推理服务器
框架支持全面(PyTorch、TF、ONNX 等)LLM 专用(HuggingFace 模型)仅 PyTorchTF、PyTorch、ONNX、TensorRT
实现语言PythonPython/C++Java/PythonC++
多模型合成Python 原生支持不支持有限Model Ensemble(基于 DAG)
自动扩缩容内置(以 Replica 为单位)依赖外部依赖外部依赖外部
LLM 优化支持 vLLM 集成Paged Attention、Continuous Batching有限TensorRT-LLM 后端
K8s 集成KubeRay Operator直接部署或 Ray 集成KServe 集成Triton Operator
批量推理@serve.batch 装饰器Continuous BatchingDynamic BatchingDynamic Batching
流式响应支持支持有限支持
学习曲线中等低(仅限 LLM)中等

选择标准总结

  • 只服务 LLM:单独使用 vLLM,或 Ray Serve + vLLM 集成
  • 需要多模型流水线:Ray Serve 是最自然的选择
  • 以 PyTorch 模型为主的简单服务:TorchServe
  • 需要极致的 GPU 性能:Triton Inference Server
  • 需要分布式多节点 GPU 服务:Ray Serve + vLLM,或 Triton + Ray Serve 集成

LLM 模型服务:vLLM + Ray Serve 集成

Ray Serve LLM 是在 Ray Serve 之上运行 vLLM 引擎的框架,既提供 OpenAI 兼容 API,又支持分布式服务与自动扩缩容。自 2025 年 Ray Serve LLM API 正式发布以来,vLLM 集成变得更加简便。

from ray import serve
from ray.serve.llm import LLMServer, LLMConfig, build_openai_app

# 定义 LLM 配置
llm_config = LLMConfig(
    model_id="meta-llama/Llama-3.1-8B-Instruct",
    engine_kwargs={
        "tensor_parallel_size": 2,
        "max_model_len": 4096,
        "gpu_memory_utilization": 0.85,
        "enforce_eager": False,
    },
    # 自动扩缩容设置
    deployment_config={
        "autoscaling_config": {
            "min_replicas": 1,
            "max_replicas": 4,
            "target_ongoing_requests": 5,
        }
    },
    accelerator_type="A100",
)

# 构建并部署 OpenAI 兼容应用
app = build_openai_app(llm_config)
serve.run(app, host="0.0.0.0", port=8000)

部署完成后,可以直接用 OpenAI SDK 调用。

# 健康检查
curl http://localhost:8000/v1/models

# 调用 Chat Completions API
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "meta-llama/Llama-3.1-8B-Instruct",
    "messages": [
      {"role": "user", "content": "请说明一下 Ray Serve 的优点。"}
    ],
    "max_tokens": 512,
    "temperature": 0.7,
    "stream": true
  }'

多个 LLM 同时服务

也可以在一个 Ray 集群中同时服务多个 LLM。

from ray.serve.llm import LLMConfig, build_openai_app

# 配置多个模型
configs = [
    LLMConfig(
        model_id="meta-llama/Llama-3.1-8B-Instruct",
        engine_kwargs={
            "tensor_parallel_size": 1,
            "gpu_memory_utilization": 0.85,
        },
        accelerator_type="A100",
    ),
    LLMConfig(
        model_id="Qwen/Qwen2.5-7B-Instruct",
        engine_kwargs={
            "tensor_parallel_size": 1,
            "gpu_memory_utilization": 0.85,
        },
        accelerator_type="A100",
    ),
]

# 将所有模型构建为单个应用
app = build_openai_app(configs)

自动扩缩容设置与资源管理

自动扩缩容基本设置

Ray Serve 的自动扩缩容器在应用层运作,基于进行中的请求数(ongoing requests)来调整 Replica 数量。设置 num_replicas="auto" 即可启用默认的自动扩缩容。

from ray import serve

@serve.deployment(
    # 自动扩缩容详细设置
    autoscaling_config={
        "min_replicas": 1,          # 最小 Replica 数
        "max_replicas": 10,         # 最大 Replica 数(相对峰值预留 20% 余量)
        "target_ongoing_requests": 5,  # 每个 Replica 的目标进行中请求数
        "upscale_delay_s": 30,      # 判定扩容前的等待时间
        "downscale_delay_s": 300,   # 判定缩容前的等待时间(保守)
        "upscaling_factor": 1.0,    # 扩容比例
        "downscaling_factor": 0.5,  # 缩容比例
        "smoothing_factor": 0.5,    # 指标平滑因子
        "metrics_interval_s": 10,   # 指标采集周期
    },
    max_ongoing_requests=10,  # 每个 Replica 的最大并发处理请求数
    ray_actor_options={
        "num_gpus": 1,
        "num_cpus": 4,
        "memory": 16 * 1024 * 1024 * 1024,  # 16GB
    },
    health_check_period_s=10,
    health_check_timeout_s=30,
    graceful_shutdown_timeout_s=60,
)
class GPUModel:
    def __init__(self):
        # 加载模型
        pass

    async def __call__(self, request):
        # 推理逻辑
        pass

自动扩缩容工作原理

自动扩缩容器的扩缩决策遵循以下公式。

desired_replicas = ceil(total_ongoing_requests / target_ongoing_requests)

举例来说,若 target_ongoing_requests=5,当前总的进行中请求数为 23 个,则需要 ceil(23/5) = 5 个 Replica。这一决策会被 upscale_delay_sdownscale_delay_s 延迟执行,以防止扩缩容剧烈波动。

资源管理策略

Zero-replica 缩容(缩容至零):长时间没有流量时,可以把 Replica 缩减到 0 以节省资源。但这会产生冷启动延迟,因此不适合实时服务。

@serve.deployment(
    autoscaling_config={
        "min_replicas": 0,   # 没有流量时缩容至 0
        "max_replicas": 5,
    },
)
class BatchModel:
    pass

Fractional GPU 分配(分数 GPU 分配):以分数为单位分配 GPU,可以在一块 GPU 上服务多个模型。

@serve.deployment(
    ray_actor_options={"num_gpus": 0.25}  # 仅使用 GPU 的 25%
)
class LightModel:
    pass

多模型服务模式(Model Composition)

Ray Serve 最强大的功能之一,就是能用 Python 代码自然地把多个模型和业务逻辑组合起来的模型合成(Model Composition)。通过 DeploymentHandle,Deployment 之间的调用表现得就像普通函数调用一样,而在内部,分布式环境下的负载均衡与序列化会以最优方式完成。

顺序流水线模式

from ray import serve

@serve.deployment(num_replicas=2)
class Preprocessor:
    def preprocess(self, text: str) -> dict:
        # 文本预处理:分词、归一化
        tokens = text.lower().split()
        return {"tokens": tokens, "length": len(tokens)}

@serve.deployment(
    num_replicas=3,
    ray_actor_options={"num_gpus": 1},
)
class Classifier:
    def __init__(self):
        from transformers import pipeline
        self.model = pipeline("text-classification", device=0)

    def classify(self, preprocessed: dict) -> dict:
        text = " ".join(preprocessed["tokens"])
        result = self.model(text)
        return {"label": result[0]["label"], "score": result[0]["score"]}

@serve.deployment(num_replicas=1)
class Postprocessor:
    def format_response(self, classification: dict) -> dict:
        return {
            "result": classification["label"],
            "confidence": round(classification["score"], 4),
            "status": "success",
        }

@serve.deployment(num_replicas=1)
class Pipeline:
    def __init__(self, preprocessor, classifier, postprocessor):
        self.preprocessor = preprocessor
        self.classifier = classifier
        self.postprocessor = postprocessor

    async def __call__(self, request):
        data = await request.json()
        text = data["text"]

        # 依次执行流水线
        preprocessed = await self.preprocessor.preprocess.remote(text)
        classified = await self.classifier.classify.remote(preprocessed)
        response = await self.postprocessor.format_response.remote(classified)
        return response

# 构建部署图
preprocessor = Preprocessor.bind()
classifier = Classifier.bind()
postprocessor = Postprocessor.bind()
app = Pipeline.bind(preprocessor, classifier, postprocessor)

Model Multiplexing 模式

这是在一个 Deployment 中动态加载多个模型进行服务的模式。在需要为数百个客户各自服务一个专属模型时很有用。

from ray import serve

@serve.deployment(
    num_replicas=2,
    max_ongoing_requests=10,
)
class MultiplexedModel:
    def __init__(self):
        self.models = {}

    def _load_model(self, model_id: str):
        if model_id not in self.models:
            # 动态加载模型(缓存管理)
            import joblib
            self.models[model_id] = joblib.load(f"/models/{model_id}.pkl")
            # 内存管理:以 LRU 缓存最多保留 10 个模型
            if len(self.models) > 10:
                oldest = next(iter(self.models))
                del self.models[oldest]
        return self.models[model_id]

    async def __call__(self, request):
        data = await request.json()
        model_id = data["model_id"]
        features = data["features"]

        model = self._load_model(model_id)
        prediction = model.predict([features])
        return {"model_id": model_id, "prediction": prediction.tolist()}

批量推理优化

使用 @serve.batch 装饰器,可以自动把多个独立请求打包成一批来处理。这是最大化 GPU 利用率的核心技巧。

import numpy as np
from ray import serve

@serve.deployment(
    num_replicas=2,
    ray_actor_options={"num_gpus": 1},
)
class BatchClassifier:
    def __init__(self):
        from transformers import AutoTokenizer, AutoModel
        import torch

        self.tokenizer = AutoTokenizer.from_pretrained(
            "bert-base-uncased"
        )
        self.model = AutoModel.from_pretrained(
            "bert-base-uncased"
        ).cuda().eval()

    @serve.batch(max_batch_size=32, batch_wait_timeout_s=0.1)
    async def handle_batch(self, texts: list[str]) -> list[dict]:
        import torch

        # 批量分词
        inputs = self.tokenizer(
            texts,
            padding=True,
            truncation=True,
            max_length=512,
            return_tensors="pt",
        ).to("cuda")

        # 批量推理
        with torch.no_grad():
            outputs = self.model(**inputs)
            embeddings = outputs.last_hidden_state[:, 0, :].cpu().numpy()

        # 将结果拆分为各自的响应
        results = []
        for i, emb in enumerate(embeddings):
            results.append({
                "embedding": emb.tolist()[:10],  # 仅返回部分
                "batch_size": len(texts),
            })
        return results

    async def __call__(self, request):
        data = await request.json()
        return await self.handle_batch(data["text"])

批量推理调优要点

  • max_batch_size:根据 GPU 内存调整。过大会 OOM,过小则 GPU 利用率下降
  • batch_wait_timeout_s:即使批次没有填满,超过这个时间也会开始处理。是延迟与吞吐量之间的权衡
  • max_ongoing_requests 设置得比 max_batch_size 更大,让批次能够充分形成

Kubernetes 部署(KubeRay Operator)

KubeRay 架构

KubeRay 是用于在 Kubernetes 中管理 Ray 工作负载的 Operator,提供三种 CRD。

  • RayCluster:管理 Ray 集群的生命周期
  • RayJob:执行一次性批处理作业
  • RayService:管理 Ray Serve 应用的服务(支持无中断升级)

RayService 部署 YAML

apiVersion: ray.io/v1
kind: RayService
metadata:
  name: llm-serving
  namespace: ml-serving
spec:
  # Serve 应用配置
  serveConfigV2: |
    applications:
      - name: llm-app
        route_prefix: /
        import_path: serve_app:app
        runtime_env:
          working_dir: "https://github.com/my-org/serve-apps/archive/main.zip"
          pip:
            - transformers>=4.40.0
            - torch>=2.2.0
            - vllm>=0.6.0
            - ray[serve]>=2.40.0
        deployments:
          - name: LLMDeployment
            num_replicas: auto
            autoscaling_config:
              min_replicas: 1
              max_replicas: 4
              target_ongoing_requests: 5
              upscale_delay_s: 30
              downscale_delay_s: 300
            max_ongoing_requests: 10
            ray_actor_options:
              num_gpus: 1
              num_cpus: 4

  # Ray 集群配置
  rayClusterConfig:
    rayVersion: '2.40.0'
    headGroupSpec:
      rayStartParams:
        dashboard-host: '0.0.0.0'
        num-gpus: '0'
      template:
        spec:
          containers:
            - name: ray-head
              image: rayproject/ray-ml:2.40.0-py310-gpu
              ports:
                - containerPort: 6379
                  name: gcs-server
                - containerPort: 8265
                  name: dashboard
                - containerPort: 8000
                  name: serve
              resources:
                limits:
                  cpu: '4'
                  memory: '16Gi'
                requests:
                  cpu: '2'
                  memory: '8Gi'

    workerGroupSpecs:
      - replicas: 2
        minReplicas: 1
        maxReplicas: 8
        groupName: gpu-workers
        rayStartParams:
          num-gpus: '1'
        template:
          spec:
            containers:
              - name: ray-worker
                image: rayproject/ray-ml:2.40.0-py310-gpu
                resources:
                  limits:
                    cpu: '8'
                    memory: '32Gi'
                    nvidia.com/gpu: '1'
                  requests:
                    cpu: '4'
                    memory: '16Gi'
                    nvidia.com/gpu: '1'
            tolerations:
              - key: 'nvidia.com/gpu'
                operator: 'Exists'
                effect: 'NoSchedule'
            nodeSelector:
              cloud.google.com/gke-accelerator: nvidia-tesla-a100

KubeRay 部署命令

# 安装 KubeRay Operator
helm repo add kuberay https://ray-project.github.io/kuberay-helm/
helm repo update
helm install kuberay-operator kuberay/kuberay-operator \
  --namespace kuberay-system \
  --create-namespace \
  --version 1.2.2

# 部署 RayService
kubectl apply -f ray-service-llm.yaml

# 检查状态
kubectl get rayservice llm-serving -n ml-serving
kubectl describe rayservice llm-serving -n ml-serving

# 查看服务日志
kubectl logs -l ray.io/serve=llm-serving -n ml-serving --tail=100

# 通过端口转发进行本地访问
kubectl port-forward svc/llm-serving-serve-svc 8000:8000 -n ml-serving

监控、日志与指标设置

Prometheus 指标采集

Ray Serve 会在每个节点上自动暴露 Prometheus 格式的指标。核心指标如下。

指标说明用途
ray_serve_num_ongoing_requests当前进行中的请求数自动扩缩容的判断依据
ray_serve_request_latency_ms请求延迟直方图p50/p95/p99 延迟监控
ray_serve_num_replicas当前活跃的 Replica 数确认扩缩容状态
ray_serve_request_counter请求总数(成功/失败)错误率告警
ray_component_rss_mb进程 RSS 内存内存泄漏检测

在 Kubernetes 中集成 Prometheus

# 通过 ServiceMonitor 采集 Ray 指标
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: ray-serve-monitor
  namespace: ml-serving
spec:
  selector:
    matchLabels:
      ray.io/serve: llm-serving
  endpoints:
    - port: metrics
      interval: 15s
      path: /metrics
  namespaceSelector:
    matchNames:
      - ml-serving

日志设置

Ray Serve 的日志默认保存在 /tmp/ray/session_latest/logs/serve/ 目录下。在 Kubernetes 环境中,建议用 Loki + Promtail 组合构建集中式日志管理。

import logging
from ray import serve

logger = logging.getLogger("ray.serve")

@serve.deployment
class MonitoredModel:
    def __init__(self):
        self.request_count = 0

    async def __call__(self, request):
        self.request_count += 1
        data = await request.json()

        logger.info(
            f"Request #{self.request_count} received",
            extra={
                "request_id": request.headers.get("X-Request-ID", "unknown"),
                "model": "monitored-model",
            },
        )

        try:
            result = self._predict(data)
            logger.info(f"Request #{self.request_count} completed successfully")
            return result
        except Exception as e:
            logger.error(
                f"Request #{self.request_count} failed: {str(e)}",
                exc_info=True,
            )
            raise

    def _predict(self, data):
        # 推理逻辑
        return {"status": "ok"}

内存分析

当怀疑存在内存泄漏时,可以使用 memray 进行分析。

# 启用内存分析
export RAY_SERVE_ENABLE_MEMORY_PROFILING=1

# 查看分析结果
ls /tmp/ray/session_latest/logs/serve/*.bin

# 自定义延迟直方图分桶
export RAY_SERVE_REQUEST_LATENCY_BUCKETS_MS="5,10,25,50,100,250,500,1000,2500,5000"

故障排查与运维注意事项

常见问题与解决方案

1. OOM(内存溢出)错误引发的连锁故障

这是 24/7 服务环境中最致命的问题。当内存不足时,Ray 会重启 Deployment,但随着重启间隔越来越短,可能会发生大部分请求失败的故障连锁反应(failure spiral)。

# 预防策略:显式声明资源限制
@serve.deployment(
    ray_actor_options={
        "num_gpus": 1,
        "memory": 16 * 1024 * 1024 * 1024,  # 显式声明为 16GB
    },
    # 通过健康检查提早发现异常状态
    health_check_period_s=10,
    health_check_timeout_s=30,
)
class SafeModel:
    def __init__(self):
        import torch
        # 记录 GPU 内存使用量
        if torch.cuda.is_available():
            allocated = torch.cuda.memory_allocated() / 1e9
            reserved = torch.cuda.memory_reserved() / 1e9
            logger.info(
                f"GPU memory - allocated: {allocated:.2f}GB, "
                f"reserved: {reserved:.2f}GB"
            )

2. GPU 内存碎片化

在集成 vLLM 时,默认会预留 GPU 显存的 90%。如果系统级预留内存超过 10%,就需要调低 gpu_memory_utilization 的值。

# 调整 gpu_memory_utilization
llm_config = LLMConfig(
    model_id="meta-llama/Llama-3.1-8B-Instruct",
    engine_kwargs={
        "gpu_memory_utilization": 0.80,  # 从 90% 降到 80%
        "max_model_len": 2048,           # 限制上下文长度
    },
)

3. 多节点 GPU 服务时的通信错误

在多节点张量并行处理时,节点间网络配置问题经常发生。

# 检查 NCCL 环境变量
export NCCL_DEBUG=INFO
export NCCL_SOCKET_IFNAME=eth0
export NCCL_IB_DISABLE=1  # 在没有 InfiniBand 的环境中

4. RayService 终止失败状态

当 RayService 陷入终止失败状态(terminal failed state)时,即便更新 spec 也不会触发重试。这种情况下必须删除 RayService 后重新创建。

# 检查失败状态
kubectl get rayservice llm-serving -n ml-serving -o jsonpath='{.status.serviceStatus}'

# 恢复:删除后重新创建
kubectl delete rayservice llm-serving -n ml-serving
kubectl apply -f ray-service-llm.yaml

5. 自动扩缩容器震荡(Oscillation)

当流量剧烈变化时,扩容/缩容可能反复发生,导致性能不稳定。

# 防止震荡的设置
autoscaling_config={
    "upscale_delay_s": 60,        # 增加扩容等待时间
    "downscale_delay_s": 600,     # 大幅增加缩容等待时间
    "smoothing_factor": 0.3,      # 降低对指标变化的敏感度
    "downscaling_factor": 0.3,    # 每次只缩容 30%
}

故障案例与恢复流程

案例 1:模型更新期间服务中断

情况:更新了 RayService 的 serveConfigV2,但新模型超出了 GPU 内存,导致所有 Replica 陷入 CrashLoopBackOff。

恢复流程

  1. 立即回滚到之前的配置:kubectl apply -f ray-service-llm-previous.yaml
  2. 确认所有 Replica 恢复正常:kubectl get pods -l ray.io/serve=llm-serving
  3. 在独立的 RayCluster 中对新模型进行内存分析
  4. 调整 gpu_memory_utilizationmax_model_len 后重新部署

案例 2:OOM 引发的连锁故障

情况:流量激增导致 Worker 节点内存耗尽。Ray 的内存监控器反复 kill 进程,引发整个服务的故障。

恢复流程

  1. 调低 min_replicas,阻断新请求流入
  2. 通过 kubectl scale 或 Cluster Autoscaler 增加 Worker 节点
  3. 分析内存占用原因:查看 ray_component_rss_mb 指标
  4. 调低 max_ongoing_requests 值,减少每个 Replica 的负载
  5. 恢复正常后逐步恢复流量

案例 3:网络分区导致 Head 节点断连

情况:Head 节点与 Worker 节点之间网络断开,无法访问 GCS(Global Control Store)。所有 Deployment 都无法响应。

恢复流程

  1. 检查 Head 节点状态:kubectl exec -it ray-head-0 -- ray status
  2. 确认网络连接恢复后,等待 Worker 节点自动重新连接(默认超时:300 秒)
  3. 若重连失败,重启 Worker Pod:kubectl delete pod <worker-pod>
  4. 若 GCS 数据丢失,需要重新创建整个 RayCluster

生产部署检查清单

这是部署前必须确认的项目清单。

资源设置

  • 是否事先对 GPU 内存使用量做过分析
  • 是否在 ray_actor_options 中明确指定了 num_gpusnum_cpusmemory
  • gpu_memory_utilization 是否设置得当(推荐:0.80~0.85)
  • 使用 Fractional GPU 时,是否验证过模型间内存冲突的可能性

自动扩缩容

  • min_replicas 是否按实际最小流量设置
  • max_replicas 是否相对峰值流量预留了 20% 的余量
  • downscale_delay_s 是否设置得足够保守(推荐至少 300 秒)
  • 是否测试过 Worker 节点自动扩缩容器(KubeRay/Cluster Autoscaler)与 Serve 自动扩缩容器之间的交互

稳定性

  • 是否设置了 health_check_period_shealth_check_timeout_s
  • graceful_shutdown_timeout_s 是否大于模型卸载所需时间
  • 是否已将 OOM 发生时的恢复流程文档化
  • 是否为 RayService 终止失败状态准备了应对 runbook

监控

  • 是否搭建了 Prometheus + Grafana 仪表盘
  • 是否设置了 ray_serve_request_latency_ms 的 p99 延迟告警
  • 是否设置了 ray_serve_request_counter 的错误率告警
  • 是否设置了内存使用量(ray_component_rss_mb)的阈值告警

部署流程

  • 是否在预发布(staging)环境中对新模型做过负载测试
  • 是否测试过 RayService 的无中断升级(rolling update)
  • 是否保留了回滚流程和此前的 YAML 配置
  • 多节点部署时是否验证过 NCCL 通信设置

结语

Ray Serve 凭借 Python 原生编程模型、强大的多模型合成、内置自动扩缩容这三大核心优势,成为生产级模型服务平台的有力选项。尤其是通过 vLLM 集成实现的 LLM 服务、通过 KubeRay 实现的 Kubernetes 原生部署,让 MLOps 团队能够高效运维复杂的推理基础设施。

不过在运维中,也存在 OOM 连锁故障、自动扩缩容器震荡、RayService 终止失败状态等特有的陷阱,因此提前进行充分的负载测试与故障模拟、并将恢复流程清晰地文档化是必不可少的。希望本文介绍的配置与模式,能成为生产环境 Ray Serve 运维的一个起点。

参考资料

현재 단락 (1/537)

在生产环境中服务 ML 模型,与训练是完全不同的工程领域。单一模型的服务用 Flask 或 FastAPI 也能做到,但在需要同时服务多个模型、根据流量自动扩缩容、高效管理 GPU 资源,还要处理故障...

작성 글자: 0원문 글자: 17,025작성 단락: 0/537