Ray Serve 是依托于 Ray 分布式计算框架之上构建的模型在线服务库,提供基于给定模型构建高性能、低延迟在线推理服务的能力。基于 Ray Serve 构建在线推理服务具有如下优势:
说明
现阶段 EMR on VKE 形态仅支持在已创建的 Ray Cluster 中部署 Ray Serve 应用,不支持通过 RayService 方式部署。
参考 EMR Ray on VKE 产品文档 在集群详情页通过 “服务列表 - Ray - 部署拓扑 - KubeRayOperator - 添加 Ray Cluster” 路径新建 Ray Cluster 集群,并采用 YAML 方式新建。鉴于 Ray Serve 应用需开放端口以向外提供 HTTP 服务,您需在 YAML 模板里修改 Ingress 配置并添加以下内容:
- backend: service: name: ingress-release-name-head-svc port: number: 8000 path: /ingress-namespace/ingress-release-name-serve/(.*) pathType: Exact
当 Ray Cluster 集群创建成功后,您需跳转至 VKE 产品控制台登录集群的 head 节点,然后执行 serve deploy
命令提交您的 Ray Serve 应用。
vLLM 和 Triton Inference Server(严格来说是 Triton Inference Server + Backend) 是目前市面上主流的两款推理加速引擎,分别针对不同场景提供了高效的解决方案。二者核心的区别如下表所示:
vLLM | Triton | |
---|---|---|
功能定位 | 专为 LLM 推理设计,优化高吞吐、低显存占用场景 | 通用推理服务器,支持多模型、多框架混合部署,注重灵活性和企业级功能 |
模型支持 | 专注于 Transformer 架构,但现阶段仅支持 pyTorch 框架模型 | 支持多种深度学习框架模型,包括 TensorFlow、PyTorch、ONNX 等,以及其他类型模型,如计算机视觉模型、语音模型、语言模型等 |
性能优化 |
| 通过动态批处理、多 GPU 并行推理等技术提升服务吞吐量,同时配合 TensorRT、ONNX 等 Backend 降低延迟 |
部署难度 | 相对容易,对于一些简单场景甚至无需复杂配置即可启动 | 相对复杂,需要编写一系列配置文件来描述模型的输入输出、数据类型、批大小等 |
尽管 vLLM 和 Triton 在推理场景中表现出卓越性能,但它们主要聚焦于单机场景,而模型在线推理通常需要多机分布式协作,以保障服务的可用性和可扩展性。通过与 Ray Serve 集成,可在在发挥 vLLM 和 Triton 各自固有优势的同时,弥补二者在分布式场景下的不足。
vLLM 是由加州大学伯克利分校(UC Berkeley)开源的一款具备高吞吐量和内存高效性的 LLM 推理与服务引擎。该引擎借助 PagedAttention、动态批处理、多 GPU 并行推理等多种优化技术,针对 LLM 场景实现了快速、灵活且易用的推理与服务,您可以访问 官方文档 了解关于 vLLM 的更多信息。
Ray Serve 自 2.43 版本开始对 vLLM 提供了原生支持。通过集成 vLLM,在发挥 Ray Serve 固有优势的同时,能够针对 LLM Serving 场景在推理速度和资源利用率等方面进行进一步优化。
说明
LLM APIs 作为 Ray 新引入特性,极大简化了 Ray Data/Serve 集成推理加速引擎(例如 vLLM、SGLang)部署 LLM 的复杂度,但相关 API 也在快速迭代和演进中,如果上述示例不能正常运行,您可以访问 官方文档 了解最新的 API 定义。
本小节以 Llama 3.2 模型介绍如何将 Ray Serve 与 vLLM 进行集成,示例如下:
from ray.serve.llm import LLMConfig, LLMServer, LLMRouter llm_config = LLMConfig( model_loading_config=dict( model_id="meta-llama/Llama-3.2-1B-Instruct", model_source="/opt/workspace/models/llama/Llama-3.2-1B-Instruct" ), deployment_config=dict( autoscaling_config=dict( min_replicas=1, max_replicas=5, ) ), # Pass the desired accelerator type (e.g. A10G, L4, etc.) accelerator_type="A10G", # You can customize the engine arguments (e.g. vLLM engine kwargs) engine_kwargs=dict( tensor_parallel_size=2, pipeline_parallel_size=2, dtype='half' ) ) # Deploy the application deployment = LLMServer \ .as_deployment(llm_config.get_serve_options(name_prefix="vLLM:")) \ .bind(llm_config) app = LLMRouter.as_deployment().bind([deployment])
通过执行 serve deploy
命令,可将上述 Ray Serve 应用部署至目标 Ray Cluster 集群。应用成功启动后,可通过以下 POST 请求向模型发送推理请求:
curl --location 'http://127.0.0.1:8000/v1/chat/completions' \ --header 'Content-Type: application/json' \ --data '{ "model": "meta-llama/Llama-3.2-1B-Instruct", "messages": [ { "role": "user", "content": "介绍一下 Ray Serve 集成 vLLM 的优势" } ] }'
Triton Inference Server (简称 Triton)是 Nvidia 推出的高性能推理服务器,支持多种模型框架和硬件平台,关于 Triton 的更多内容可以参考 官方文档。Triton 与 Ray Serve 在功能定位方面存在相同之处,不过二者也各有优势:
如下图所示,通过将 Ray Serve 与 Triton 集成能够让二者的优势形成互补:
本小节将阐述如何实现 Ray Serve 与 Triton 的集成。在集成模式下,Ray Serve 主要承担流量承接、负载均衡、模型编排以及弹性伸缩等职责;而 Triton 则作为单机版的模型推理服务,具备模型加载、推理及加速等功能。 以 Llama 3.2 模型为例,在开始集成前,你需要确保完成:
如下所示,TensorRT-LLM Backend 内置的模型集成配置模板位于 all_models/inflight_batcher_llm
目录下,主要包含 4 个模块,分别对应模型执行过程的不同阶段。
. |-- ensemble | |-- 1 | `-- config.pbtxt |-- postprocessing | |-- 1 | | `-- model.py | `-- config.pbtxt |-- preprocessing | |-- 1 | | `-- model.py | `-- config.pbtxt `-- tensorrt_llm |-- 1 | |-- config.json | |-- model.py | `-- rank0.engine `-- config.pbtxt
说明
注意
num_gpus
参数,否则 Ray Serve 并不会将 Deployment 调度部署到 GPU 节点上,从而导致 Triton 加载失败。Triton 提供了 In-Process Python API 用于支持 Python 生态与 Triton 进行集成,相较于发送 HTTP 请求的方式更为便捷。下面的示例通过 Triton In-Process Python API 实现了 Ray Serve 与 Triton 的集成:
import ctypes from typing import Iterable import numpy as np import tritonserver from fastapi import FastAPI from ray import serve api = FastAPI() @serve.deployment( ray_actor_options=dict( num_gpus=1 ) ) @serve.ingress(api) class Generator: def __init__(self, model_path: str): import torch assert torch.cuda.is_available(), RuntimeError("CUDA is not available") self._server = tritonserver.Server( tritonserver.Options( model_repository=model_path, log_info=True, log_warn=True, log_error=True ) ) self._server.start(wait_until_ready=True) self._model = self._server.model("ensemble") @api.get("/generate") def generate(self, query: str): if not self._model.ready(): raise RuntimeError("Model is not ready, Please try again later.") resp = list(self._model.infer(inputs={ "text_input": [[query]], "max_tokens": np.array([[1024]], dtype=np.int32) }))[0] return self._to_string(resp.outputs["text_output"]) def _to_string(self, tensor: tritonserver.Tensor) -> str: """ This method is copied from https://github.com/triton-inference-server/server """ ... app = Generator.bind("/opt/workspace/models/llama/triton")
通过执行 serve deploy
命令,可将上述 Ray Serve 应用部署至目标 Ray Cluster 集群。应用成功启动后,可通过以下 POST 请求向模型发送推理请求:
curl --location 'http://127.0.0.1:8000/v1/chat/completions' \ --header 'Content-Type: application/json' \ --data '{ "model": "meta-llama/Llama-3.2-1B-Instruct", "messages": [ { "role": "user", "content": "介绍一下 Ray Serve 集成 Triton Inference Server 的优势" } ] }'