开发工作流#

本页面介绍开发 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 "https://:8000/?name=Ray"
# Hello, Ray! Hello, Ray!

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

^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 Client

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

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

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

这通过 Ray Client 连接到远程集群,上传 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 应用程序的详细信息。一旦您准备好部署到生产环境,请参阅 生产指南