处理依赖#
添加运行时环境#
导入路径(例如,text_ml:app)必须能在运行时被 Serve 导入。在本地运行时,此路径可能位于您当前的目录中。然而,在集群上运行时,您还需要确保此路径可被导入。将代码构建到集群的容器镜像中(有关更多详细信息,请参阅 集群配置)或者使用一个带有 远程 URI 的 runtime_env,该 URI 托管了远程存储中的代码。
有关示例,请参阅 GitHub 上的 Text ML Models 应用程序。您可以即使在本地没有代码的情况下,使用此配置文件将文本摘要和翻译应用程序部署到您自己的 Ray 集群。
import_path: text_ml:app
runtime_env:
working_dir: "https://github.com/ray-project/serve_config_examples/archive/HEAD.zip"
pip:
- torch
- transformers
注意
您还可以将部署图打包成一个独立的 Python 包,然后使用 PYTHONPATH 来导入,以在本地机器上提供位置无关性。然而,最佳实践是使用 runtime_env,以确保集群中所有机器之间的一致性。
每个部署的依赖项#
Ray Serve 还支持服务具有不同(甚至可能冲突)的 Python 依赖项的部署。例如,您可以同时服务一个使用旧版 Tensorflow 1 的部署和一个使用 Tensorflow 2 的部署。
这在 Mac OS 和 Linux 上通过 Ray 的 运行时环境 功能得到支持。与所有其他 Ray Actor 选项一样,通过部署中的 ray_actor_options 传入运行时环境。请务必先运行 pip install "ray[default]" 以确保 Runtime Environments 功能已安装。
示例
import requests
from starlette.requests import Request
from ray import serve
from ray.serve.handle import DeploymentHandle
@serve.deployment
class Ingress:
def __init__(
self, ver_25_handle: DeploymentHandle, ver_26_handle: DeploymentHandle
):
self.ver_25_handle = ver_25_handle
self.ver_26_handle = ver_26_handle
async def __call__(self, request: Request):
if request.query_params["version"] == "25":
return await self.ver_25_handle.remote()
else:
return await self.ver_26_handle.remote()
@serve.deployment
def requests_version():
return requests.__version__
ver_25 = requests_version.options(
name="25",
ray_actor_options={"runtime_env": {"pip": ["requests==2.25.1"]}},
).bind()
ver_26 = requests_version.options(
name="26",
ray_actor_options={"runtime_env": {"pip": ["requests==2.26.0"]}},
).bind()
app = Ingress.bind(ver_25, ver_26)
serve.run(app)
assert requests.get("http://127.0.0.1:8000/?version=25").text == "2.25.1"
assert requests.get("http://127.0.0.1:8000/?version=26").text == "2.26.0"
提示
避免动态安装从源代码安装的包:这些包可能安装缓慢,并在安装过程中耗尽所有资源,导致 Ray 集群出现问题。请考虑在私有存储库或 Docker 镜像中预编译此类包。
部署所需的依赖项可能与驱动程序(运行 Serve API 调用的程序)中安装的依赖项不同。在这种情况下,您应该在类中使用延迟导入,以避免在驱动程序中导入不可用的包。即使不使用运行时环境,也适用此规则。
示例
from ray import serve
@serve.deployment
class MyDeployment:
def __call__(self, model_path):
from my_module import my_model
self.model = my_model.load(model_path)