配置 Ray#

备注

要运行Java应用程序,请参阅 Java 应用程序

本页讨论了配置 Ray 的各种方式,包括通过 Python API 和命令行。查看 ray.init文档 以获取配置的完整概述。

重要

对于多节点设置,您必须在命令行上首先运行 ray start 以在机器上启动 Ray 集群服务,然后在 Python 中运行 ray.init 以连接到集群服务。在单台机器上,您可以不运行 ray start 而直接运行 ray.init(),这将同时启动 Ray 集群服务并连接到它们。

集群资源#

Ray 默认检测可用资源。

import ray

# This automatically detects available resources in the single machine.
ray.init()

如果不是在集群模式下运行,您可以通过 ray.init 指定集群资源覆盖,如下所示。

# If not connecting to an existing cluster, you can specify resources overrides:
ray.init(num_cpus=8, num_gpus=1)
# Specifying custom resources
ray.init(num_gpus=1, resources={'Resource1': 4, 'Resource2': 16})

从命令行启动 Ray 时,将 --num-cpus--num-gpus 标志传递给 ray start。您还可以指定自定义资源。

# To start a head node.
$ ray start --head --num-cpus=<NUM_CPUS> --num-gpus=<NUM_GPUS>

# To start a non-head node.
$ ray start --address=<address> --num-cpus=<NUM_CPUS> --num-gpus=<NUM_GPUS>

# Specifying custom resources
ray start [--head] --num-cpus=<NUM_CPUS> --resources='{"Resource1": 4, "Resource2": 16}'

如果使用命令行,请按以下方式连接到 Ray 集群:

# Connect to ray. Notice if connected to existing cluster, you don't specify resources.
ray.init(address=<address>)

备注

如果通过 ray.remote()task.options()/actor.options() 在任务/角色上设置了 num_cpus,Ray 会设置环境变量 OMP_NUM_THREADS=<num_cpus>。如果未指定 num_cpus,Ray 会设置 OMP_NUM_THREADS=1;这是为了避免在许多工作线程中性能下降(问题 #6998)。您也可以通过显式设置 OMP_NUM_THREADS 来覆盖 Ray 的默认设置。OMP_NUM_THREADS 通常在 numpy、PyTorch 和 Tensorflow 中用于执行多线程线性代数。在多工作线程设置中,我们希望每个工作线程有一个线程,而不是每个工作线程有多个线程,以避免争用。其他一些库可能有自己配置并行性的方式。例如,如果您使用 OpenCV,您应该使用 cv2.setNumThreads(num_threads) 手动设置线程数(设置为 0 以禁用多线程)。

日志记录和调试#

每个 Ray 会话将有一个唯一的名称。默认情况下,名称是 session_{timestamp}_{pid}timestamp 的格式是 %Y-%m-%d_%H-%M-%S_%f``(详见 `Python 时间格式 <strftime.org>`__);pid 属于启动进程(调用 ``ray.init() 的进程或通过 ray start 在 shell 中执行的 Ray 进程)。

对于每个会话,Ray 会将所有临时文件放置在 会话目录 下。会话目录*根临时路径*(默认为 /tmp/ray)的子目录,因此默认的会话目录是 /tmp/ray/{ray_session_name}。您可以按名称排序以找到最新的会话。

通过向 ray start 传递 --temp-dir={你的临时路径} 来更改 根临时目录

(目前没有稳定的方法在调用 ray.init() 时更改根临时目录,但如果需要,可以向 ray.init() 提供 _temp_dir 参数。)

查看 日志目录结构 了解更多详情。

端口配置#

Ray 要求集群中的节点之间进行双向通信。每个节点打开特定的端口以接收传入的网络请求。

所有节点#

  • --node-manager-port: 节点管理器的 Raylet 端口。默认值:随机值。

  • --object-manager-port: 对象管理器的 Raylet 端口。默认值:随机值。

  • --runtime-env-agent-port: 运行时环境代理的 Raylet 端口。默认值:随机值。

节点管理器和对象管理器作为独立的进程运行,各自拥有用于通信的端口。

以下选项指定了仪表板代理进程使用的端口。

  • --dashboard-agent-grpc-port: 监听grpc的端口。默认值:随机值。

  • --dashboard-agent-listen-port: 监听http的端口。默认值: 52365。

  • --metrics-export-port: 用于暴露 Ray 指标的端口。默认值:随机值。

以下选项指定了跨机器的工作进程使用的端口范围。范围内的所有端口都应开放。

  • --min-worker-port: 工作进程可以绑定的最小端口号。默认值:10002。

  • --max-worker-port: 工作线程可以绑定的最大端口号。默认值:19999。

端口号是 Ray 如何区分单个节点上多个工作者的输入和输出的方式。每个工作者将在一个端口号上接收输入和输出。因此,例如,默认情况下,每个节点最多有 10,000 个工作者,无论 CPU 数量如何。

通常建议为 Ray 提供一系列可能的 worker 端口,以防这些端口中的任何一个恰好被机器上的其他程序使用。然而,在调试时,明确指定一个短的 worker 端口列表(如 --worker-port-list=10000,10001,10002,10003,10004)是有用的(注意,这将限制 worker 的数量,就像指定一个狭窄的范围一样)。

头节点#

除了上述指定的端口外,主节点还需要打开几个额外的端口。

  • --port: Ray 的端口(GCS 服务器)。头节点将启动一个监听此端口的 GCS 服务器。默认值:6379。

  • --ray-client-server-port: Ray Client Server 的监听端口。默认值: 10001。

  • --redis-shard-ports: 非主Redis分片的端口列表,以逗号分隔。默认值:随机值。

  • --dashboard-grpc-port: 仪表盘使用的 gRPC 端口。默认值:随机值。

  • 如果 --include-dashboard 为真(默认),则头节点必须打开 --dashboard-port。默认值:8265。

如果 --include-dashboard 为真,但 --dashboard-port 在头节点上未打开,您将反复遇到

WARNING worker.py:1114 -- The agent on node <hostname of node that tried to run a task> failed with the following error:
Traceback (most recent call last):
  File "/usr/local/lib/python3.8/dist-packages/grpc/aio/_call.py", line 285, in __await__
    raise _create_rpc_error(self._cython_call._initial_metadata,
grpc.aio._call.AioRpcError: <AioRpcError of RPC that terminated with:
  status = StatusCode.UNAVAILABLE
  details = "failed to connect to all addresses"
  debug_error_string = "{"description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":4165,"referenced_errors":[{"description":"failed to connect to all addresses","file":"src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc","file_line":397,"grpc_status":14}]}"

(此外,您将无法访问仪表板。)

如果你看到那个错误,检查 --dashboard-port 是否可以通过 nc``nmap``(或你的浏览器)访问。

$ nmap -sV --reason -p 8265 $HEAD_ADDRESS
Nmap scan report for compute04.berkeley.edu (123.456.78.910)
Host is up, received reset ttl 60 (0.00065s latency).
rDNS record for 123.456.78.910: compute04.berkeley.edu
PORT     STATE SERVICE REASON         VERSION
8265/tcp open  http    syn-ack ttl 60 aiohttp 3.7.2 (Python 3.8)
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .

请注意,仪表盘作为一个独立的子进程运行,可能会在后台无提示地崩溃,因此即使你之前检查了8265端口,该端口现在可能已经关闭(因为不再有服务在其上运行这一平淡无奇的原因)。这也意味着,如果该端口无法访问,如果你执行 ray stopray start,由于仪表盘的重启,该端口可能会再次变得可访问。

如果你不想要仪表盘,设置 --include-dashboard=false

TLS 认证#

Ray 可以配置为在其 gRPC 通道上使用 TLS。这意味着连接到 Ray 头节点需要一组适当的凭证,并且各个进程(客户端、头节点、工作节点)之间交换的数据是加密的。

在TLS中,私钥和公钥用于加密和解密。前者由所有者保密,后者与另一方共享。这种模式确保只有预期的接收者才能读取消息。

证书颁发机构(CA)是一个可信的第三方,用于认证公钥所有者的身份。CA颁发的数字证书包含公钥本身、公钥所有者的身份以及证书的到期日期。请注意,如果公钥所有者不想从CA获取数字证书,他们可以使用OpenSSL等工具生成自签名证书。

要获得数字证书,公钥的所有者必须生成一个证书签名请求(CSR)。CSR包含有关公钥所有者的信息以及公钥本身。对于Ray,实现成功的TLS加密需要一些额外的步骤。

以下是使用自签名证书为静态 Kubernetes Ray 集群添加 TLS 身份验证的分步指南:

步骤 1:为 CA 生成私钥和自签名证书#

openssl req -x509 \
            -sha256 -days 3650 \
            -nodes \
            -newkey rsa:2048 \
            -subj "/CN=*.ray.io/C=US/L=San Francisco" \
            -keyout ca.key -out ca.crt

使用以下命令对私钥文件和自签名证书文件进行编码,然后将编码后的字符串粘贴到secret.yaml中。

cat ca.key | base64
cat ca.crt | base64

# 或者,该命令会自动编码并创建CA密钥对的密钥。kubectl create secret generic ca-tls –from-file=ca.crt=<ca.crt的路径> –from-file=ca.key=<ca.key的路径>

步骤 2:为 Ray 头节点和工作节点生成单独的私钥和自签名证书#

YAML 文件 中有一个名为 tls 的 ConfigMap,其中包含两个 shell 脚本:gencert_head.shgencert_worker.sh。这些脚本为每个部署中的 head 和 worker Pod 的 initContainer 生成私钥和自签名证书文件(tls.keytls.crt)。通过使用 initContainer,我们可以动态地将 POD_IP 检索到 [alt_names] 部分。

脚本执行以下步骤:首先,生成一个2048位的RSA私钥并保存为 /etc/ray/tls/tls.key。然后,使用 tls.key 文件和 csr.conf 配置文件生成一个证书签名请求(CSR)。最后,使用证书颁发机构(CA)的密钥对(ca.key ca.crt)和CSR(ca.csr)创建一个自签名证书(tls.crt)。

步骤 3:为 Ray 头节点和工作节点设置环境变量以启用 TLS#

通过设置环境变量可以启用TLS。

  • RAY_USE_TLS: 使用/不使用 TLS 的 1 或 0。如果设置为 1,则必须设置以下所有环境变量。默认值:0。

  • RAY_TLS_SERVER_CERT: 证书文件 (tls.crt) 的位置,该文件用于向其他端点展示以实现相互认证。

  • RAY_TLS_SERVER_KEY: 私钥文件 (tls.key) 的位置,这是向其他端点证明您是给定证书的授权用户的加密手段。

  • RAY_TLS_CA_CERT: CA 证书文件 (ca.crt) 的位置,它允许 TLS 决定一个端点的证书是否由正确的机构签名。

步骤 4:验证 TLS 认证#

# Log in to the worker Pod
kubectl exec -it ${WORKER_POD} -- bash

# Since the head Pod has the certificate of the full qualified DNS resolution for the Ray head service, the connection to the worker Pods
# is established successfully
ray health-check --address service-ray-head.default.svc.cluster.local:6379

# Since service-ray-head hasn't added to the alt_names section in the certificate, the connection fails and an error
# message similar to the following is displayed: "Peer name service-ray-head is not in peer certificate".
ray health-check --address service-ray-head:6379

# After you add `DNS.3 = service-ray-head` to the alt_names sections and deploy the YAML again, the connection is able to work.

启用 TLS 会导致性能下降,这是由于相互认证和加密带来的额外开销。测试表明,这种开销在小工作负载下很大,而在大工作负载下相对较小。确切的开销取决于您的工作负载性质。

Java 应用程序#

重要

对于多节点设置,您必须在命令行上首先运行 ray start 以在机器上启动 Ray 集群服务,然后在 Java 中调用 Ray.init() 以连接到集群服务。在单台机器上,您可以不运行 ray start 而直接运行 Ray.init(),这将同时启动 Ray 集群服务并连接到它们。

代码搜索路径#

如果你想在多节点集群中运行一个Java应用程序,你必须在你的驱动程序中指定代码搜索路径。代码搜索路径是告诉Ray在启动Java工作进程时从哪里加载jar文件。在运行你的代码之前,你的jar文件必须被分发到Ray集群所有节点的相同路径上。

$ java -classpath <classpath> \
    -Dray.address=<address> \
    -Dray.job.code-search-path=/path/to/jars/ \
    <classname> <args>

这里的 /path/to/jars/ 指向一个包含 jar 文件的目录。目录中的所有 jar 文件都将被 worker 加载。你也可以为这个参数提供多个目录。

$ java -classpath <classpath> \
    -Dray.address=<address> \
    -Dray.job.code-search-path=/path/to/jars1:/path/to/jars2:/path/to/pys1:/path/to/pys2 \
    <classname> <args>

如果您在单节点集群中运行Java应用程序,则无需配置代码搜索路径。

更多信息请参见 Driver Options 下的 ray.job.code-search-path

备注

目前,我们在单机模式下运行Java应用程序时,不提供配置Ray的方法。如果您需要配置Ray,请先运行 ray start 来启动Ray集群。

驱动选项#

Java 驱动程序的选项是有限的。它们不是用于配置 Ray 集群,而是仅用于配置驱动程序。

Ray 使用 Typesafe Config 来读取选项。设置选项有几种方式:

  • 系统属性。您可以通过在驱动程序命令行中添加 -Dkey=value 格式的选项来配置系统属性,或者在调用 Ray.init() 之前通过调用 System.setProperty("key", "value"); 来配置。

  • 一个 HOCON 格式 配置文件。默认情况下,Ray 会尝试读取 classpath 根目录下的 ray.conf 文件。你可以通过设置系统属性 ray.config-file 为文件路径来自定义文件的位置。

备注

通过系统属性配置的选项比配置文件中的选项具有更高的优先级。

可用驱动选项列表:

  • ray.address

    • 如果驱动程序连接到现有的 Ray 集群,则提供集群地址。如果为空,将创建一个新的 Ray 集群。

    • 类型: 字符串

    • 默认值:空字符串。

  • ray.job.代码搜索路径

    • Java worker 加载代码的路径。目前仅支持目录。您可以使用 : 分隔指定一个或多个目录。如果您在单机模式或本地模式下运行 Java 应用程序,则无需配置代码搜索路径。如果指定了代码搜索路径,它也用于加载 Python 代码。这对于 跨语言 是必需的。如果指定了代码搜索路径,您只能运行可以在代码搜索路径中找到的 Python 远程函数。

    • 类型: 字符串

    • 默认值:空字符串。

    • 示例: /path/to/jars1:/path/to/jars2:/path/to/pys1:/path/to/pys2

  • ray.job.namespace

    • 此作业的命名空间。它用于作业之间的隔离。不同命名空间中的作业无法相互访问。如果未指定,将使用随机值代替。

    • 类型: 字符串

    • 默认值:一个随机的UUID字符串值。