开发工作流程#

本页描述了开发 Ray Serve 应用的推荐工作流程。如果您已准备好投入生产环境,请跳至生产指南部分。

使用 serve.run 进行本地开发#

您可以在 Python 脚本中使用 serve.run 在本地运行和测试您的应用,使用句柄以编程方式发送请求,而不是通过 HTTP。

优势

  • 自包含的 Python 便于编写本地集成测试。

  • 无需部署到云提供商或管理基础设施。

缺点

  • 不测试 HTTP 端点。

  • 如果您的本地机器没有 GPU,则无法使用 GPU。

让我们看一个简单的例子。

# Filename: local_dev.py
from starlette.requests import Request

from ray import serve
from ray.serve.handle import DeploymentHandle, DeploymentResponse


@serve.deployment
class Doubler:
    def double(self, s: str):
        return s + " " + s


@serve.deployment
class HelloDeployment:
    def __init__(self, doubler: DeploymentHandle):
        self.doubler = doubler

    async def say_hello_twice(self, name: str):
        return await self.doubler.double.remote(f"Hello, {name}!")

    async def __call__(self, request: Request):
        return await self.say_hello_twice(request.query_params["name"])


app = HelloDeployment.bind(Doubler.bind())

我们可以添加以下代码以在本地部署和测试 Serve。

handle: DeploymentHandle = serve.run(app)
response: DeploymentResponse = handle.say_hello_twice.remote(name="Ray")
assert response.result() == "Hello, Ray! Hello, Ray!"

使用 HTTP 请求进行本地开发#

您可以使用 serve run CLI 命令在本地运行和测试您的应用,使用 HTTP 发送请求(类似于如果您熟悉 Uvicorn,您可能会使用的 uvicorn 命令)。

回顾上面的例子

# Filename: local_dev.py
from starlette.requests import Request

from ray import serve
from ray.serve.handle import DeploymentHandle, DeploymentResponse


@serve.deployment
class Doubler:
    def double(self, s: str):
        return s + " " + s


@serve.deployment
class HelloDeployment:
    def __init__(self, doubler: DeploymentHandle):
        self.doubler = doubler

    async def say_hello_twice(self, name: str):
        return await self.doubler.double.remote(f"Hello, {name}!")

    async def __call__(self, request: Request):
        return await self.say_hello_twice(request.query_params["name"])


app = HelloDeployment.bind(Doubler.bind())

现在在您的终端中运行以下命令

serve run local_dev:app
# 2022-08-11 11:31:47,692 INFO scripts.py:294 -- Deploying from import path: "local_dev:app".
# 2022-08-11 11:31:50,372 INFO worker.py:1481 -- Started a local Ray instance. View the dashboard at http://127.0.0.1:8265.
# (ServeController pid=9865) INFO 2022-08-11 11:31:54,039 controller 9865 proxy_state.py:129 - Starting HTTP proxy with name 'SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-dff7dc5b97b4a11facaed746f02448224aa0c1fb651988ba7197e949' on node 'dff7dc5b97b4a11facaed746f02448224aa0c1fb651988ba7197e949' listening on '127.0.0.1:8000'
# (ServeController pid=9865) INFO 2022-08-11 11:31:55,373 controller 9865 deployment_state.py:1232 - Adding 1 replicas to deployment 'Doubler'.
# (ServeController pid=9865) INFO 2022-08-11 11:31:55,389 controller 9865 deployment_state.py:1232 - Adding 1 replicas to deployment 'HelloDeployment'.
# (HTTPProxyActor pid=9872) INFO:     Started server process [9872]
# 2022-08-11 11:31:57,383 SUCC scripts.py:315 -- Deployed successfully.

serve run 命令会阻塞终端,可以使用 Ctrl-C 取消。通常,不应在多个终端同时运行 serve run,除非每个 serve run 针对的是一个独立的正在运行的 Ray 集群。

现在 Serve 正在运行,我们可以向应用发送 HTTP 请求。为简单起见,我们将仅使用 curl 命令从另一个终端发送请求。

curl -X PUT "http://localhost:8000/?name=Ray"
# Hello, Ray! Hello, Ray!

测试完成后,您可以通过中断 serve run 命令来关闭 Ray Serve(例如,使用 Ctrl-C)

^C2022-08-11 11:47:19,829       INFO scripts.py:323 -- Got KeyboardInterrupt, shutting down...
(ServeController pid=9865) INFO 2022-08-11 11:47:19,926 controller 9865 deployment_state.py:1257 - Removing 1 replicas from deployment 'Doubler'.
(ServeController pid=9865) INFO 2022-08-11 11:47:19,929 controller 9865 deployment_state.py:1257 - Removing 1 replicas from deployment 'HelloDeployment'.

请注意,重新运行 serve run 会重新部署所有部署。为了防止重新部署代码未更改的部署,您可以使用 serve deploy;详情请参阅生产指南

本地测试模式#

注意

这是一项实验性功能。

Ray Serve 支持本地测试模式,允许您在单个进程中本地运行部署。此模式对于单元测试和调试应用逻辑非常有用,无需完整 Ray 集群的开销。要启用此模式,请在 serve.run 函数中使用 _local_testing_mode 标志

serve.run(app, _local_testing_mode=True)

此模式在后台线程中运行每个部署,并支持与在完整 Ray 集群上运行相同的大多数功能。请注意,某些功能(例如将 DeploymentResponses 转换为 ObjectRefs)在本地测试模式下不受支持。如果您遇到限制,请考虑在 GitHub 上提交功能请求。

在远程集群上测试#

要在远程集群上测试,请再次使用 serve run,但这次传入 --address 参数来指定要连接的 Ray 集群的地址。对于远程集群,此地址的形式为 ray://<head-node-ip-address>:10001;有关更多信息,请参阅Ray 客户端

从本地机器过渡到远程集群时,您需要确保集群具有与本地机器相似的环境——例如文件、环境变量和 Python 包。

让我们看一个只打包代码的简单示例。在您的本地机器上运行以下命令,将命令中的 <head-node-ip-address> 替换为您的远程集群头节点 IP 地址

serve run  --address=ray://<head-node-ip-address>:10001 --working-dir="./project/src" local_dev:app

这将使用 Ray 客户端连接到远程集群,上传 working_dir 目录,并运行您的 Serve 应用。在此,由 working_dir 指定的本地目录必须包含 local_dev.py,以便可以将其上传到集群并由 Ray Serve 导入。

一旦启动并运行,我们可以向应用发送请求

curl -X PUT http://<head-node-ip-address>:8000/?name=Ray
# Hello, Ray! Hello, Ray!

对于更复杂的依赖项,包括工作目录之外的文件、环境变量和 Python 包,您可以使用运行时环境。此示例使用 –runtime-env-json 参数

serve run  --address=ray://<head-node-ip-address>:10001 --runtime-env-json='{"env_vars": {"MY_ENV_VAR": "my-value"}, "working_dir": "./project/src", "pip": ["requests", "chess"]}' local_dev:app

您也可以在 YAML 文件中指定 runtime_env;详情请参阅serve run

接下来是什么?#

Ray dashboard 中查看您的 Serve 应用详情。一旦准备好部署到生产环境,请参阅生产指南