前言
Ray Serve 是一个可扩展的模型服务库,用于构建在线推理 API。Serve 与框架无关,因此你可以使用一个单一的工具包来服务从使用 PyTorch、TensorFlow 和 Keras 等框架构建的深度学习模型,到 Scikit-Learn 模型,再到任意 Python 业务逻辑的所有内容。它具有多项用于服务大语言模型的特性和性能优化,例如响应流、动态请求批处理、多节点 / 多 GPU 服务等。
据说OpenAI背后用Serving框架也是Ray Serve,今天继续开盲盒,看看天才们都是怎么想的。
使用示例
import requests
from starlette.requests import Request
from typing import Dict
from ray import serve
# 1: Define a Ray Serve application.
@serve.deployment
class MyModelDeployment:
def __init__(self, msg: str):
# Initialize model state: could be very large neural net weights.
self._msg = msg
def __call__(self, request: Request) -> Dict:
return {
"result": self._msg}
app = MyModelDeployment.bind(msg="Hello world!")
# 2: Deploy the application locally.
serve.run(app, route_prefix="/")
# 3: Query the application and print the result.
print(requests.get("http://localhost:8000/").json())
# {'result': 'Hello world!'}
关键概念
Deployment
deployment是 Ray Serve 中的核心概念。一个deployment包含处理传入请求的业务逻辑或机器学习模型,并且可以扩展以在 Ray 集群中运行。在运行时,一个部署由多个副本组成,这些副本是在单独的 Ray Actor(进程)中启动的类或函数的单个副本。副本的数量可以根据传入的请求负载进行增加或减少(甚至自动缩放)。
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment
class MyFirstDeployment:
# Take the message to return as an argument to the constructor.
def __init__(self, msg):
self.msg = msg
def __call__(self):
return self.msg
my_first_deployment = MyFirstDeployment.bind("Hello world!")
handle: DeploymentHandle = serve.run(my_first_deployment)
assert handle.remote().result() == "Hello world!"
Application
Application是 Ray Serve 集群中的新玩意儿,一个Application由一个或多个部署组成。其中一个部署被视为 “入口” 部署,它处理所有入站流量。说白了,就是服务的服务,帮忙串起来所有的microservice。
可以通过指定路由前缀的 HTTP 或在 Python 中使用 DeploymentHandle 来调用应用程序。
DeploymentHandle
Ray Serve 允许多个独立的部署相互调用,从而实现灵活的模型组合和扩展。在绑定一个部署时,你可以包含对其他已绑定部署的引用。然后,在运行时,这些参数中的每一个都会转换为一个 DeploymentHandle,可用于通过原生 Python API 查询该部署。下面是一个基本示例,其中入口(Ingress)部署可以调用两个下游模型。
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment
class Hello:
def __call__(self) -> str:
return "Hello"
@serve.deployment
class World:
def __call__(self) -> str:
return " world!"
@serve.deployment
class Ingress:
def __init__(self, hello_handle: DeploymentHandle, world_handle: DeploymentHandle):
self._hello_handle = hello_handle
self._world_handle = world_handle
async def __call__(self) -> str:
hello_response = self._hello_handle.remote()
world_response = self._world_handle.remote()
return (await hello_response) + (await world_response)
hello = Hello.bind()
world = World.bind()
# The deployments passed to the Ingress constructor are replaced with handles.
app = Ingress.bind(hello, world)
# Deploys Hello, World, and Ingress.
handle: DeploymentHandle = serve.run(app)
# `DeploymentHandle`s can also be used to call the ingress deployment of an application.
assert handle.remote().result() == "Hello world!"
Ray Serve Autoscaler vs Ray Autoscaler
Ray Serve 自动缩放器是一个位于 Ray 自动缩放器之上的应用程序级自动缩放器。具体来说,这意味着 Ray Serve 自动缩放器会根据请求需求要求 Ray 启动一定数量的副本 Actor。如果 Ray 自动缩放器判定没有足够的可用资源(如 CPU、GPU 等)来安置这些 Actor,它会请求更多的 Ray 节点。然后,底层的云服务提供商将响应并添加更多节点。同样,当 Ray Serve 进行缩容并终止副本 Actor 时,它会尽可能让多个节点处于空闲状态,以便 Ray 自动缩放器可以移除它们。架构图如下:
源码分析
api
- 所有暴露给用户的代码都放在了:https://github.com/ray-project/ray/blob/master/python/ray/serve/api.py
Deployment
接口定义
# 表示该API是公共的且稳定性为“稳定”
@PublicAPI(stability="stable")
def deployment(
# 要转换为部署的可调用对象(函数或类),可以为None
_func_or_class: Optional[Callable] = None,
# 应用程序内唯一标识此部署的名称。如果未提供,则使用类或函数的名称
name: Default[str] = DEFAULT.VALUE,
# 此部署的版本,默认值为DEFAULT.VALUE
version: Default[str] = DEFAULT
标签:__,handle,16,self,serve,源码,world,Ray
From: https://blog.csdn.net/weixin_43956669/article/details/145086108