配置 Ray#

注意

对于运行 Java 应用,请参阅Java 应用

本页面讨论了通过 Python API 和命令行配置 Ray 的各种方法。有关配置的完整概述,请查阅 ray.init 文档

重要

对于多节点设置,您必须首先在命令行上运行 ray start 来启动机器上的 Ray 集群服务,然后才能在 Python 中调用 ray.init 连接到集群服务。在单机上,您可以直接运行 ray.init() 而无需先运行 ray start,它会同时启动 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 会话都有一个唯一的名称。默认情况下,名称为 session_{timestamp}_{pid}timestamp 的格式为 %Y-%m-%d_%H-%M-%S_%f (详见Python 时间格式);pid 属于启动进程(调用 ray.init() 的进程或在 ray start 中由 shell 执行的 Ray 进程)。

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

通过将 --temp-dir={your temp path} 传递给 ray start 来更改 根临时目录

目前没有稳定的方法可以在调用 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 指标的端口。默认值:随机值。

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

  • --min-worker-port: worker 绑定的最小端口号。默认值:10002。

  • --max-worker-port: worker 绑定的最大端口号。默认值:19999。

端口号是 Ray 在单个节点上区分多个 worker 的输入和输出的方式。每个 worker 在一个端口号上接收输入并提供输出。因此,默认情况下,每个节点最多有 10,000 个 worker,与 CPU 数量无关。

通常,您应该为 Ray 提供一个宽泛的 worker 端口范围,以防您的机器上恰好有其他程序正在使用这些端口。然而,在调试时,明确指定一个简短的 worker 端口列表(例如 --worker-port-list=10000,10001,10002,10003,10004)会很有用。请注意,这种做法会限制 worker 的数量,就像指定一个狭窄范围一样。

Head 节点#

除了前面部分指定的端口外,head 节点还需要打开更多端口。

  • --port: Ray GCS 服务器的端口。head 节点在该端口上启动一个 GCS 服务器进行监听。默认值:6379。

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

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

  • --dashboard-grpc-port: (已弃用) 不再使用。仅保留用于向后兼容。

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

如果 --include-dashboard 为 true,但 head 节点上未打开 --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 是否可通过 ncnmap 或您的浏览器访问。

$ 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 stop 然后 ray start,由于仪表板重启,端口可能会再次变为可达。

如果您不希望使用仪表板,请设置 --include-dashboard=false

TLS 认证#

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

TLS 使用私钥和公钥进行加密和解密。所有者保密私钥,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 密钥对创建 secret。.. code-block:: bash

kubectl create secret generic ca-tls –from-file=ca.crt=<path-to-ca.crt> –from-file=ca.key=<path-to-ca.key>

步骤 2:为 Ray head 和 workers 生成独立的私钥和自签名证书#

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

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

步骤 3:为 Ray head 和 worker 设置环境变量以启用 TLS#

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

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

  • RAY_TLS_SERVER_CERT: 证书文件 (tls.crt) 的位置,Ray 将其提供给其他端点以实现相互认证。

  • 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.init() 而无需先运行 ray start。它会同时启动 Ray 集群服务并连接到它们。

代码搜索路径#

如果您想在多节点集群中运行 Java 应用,必须在您的 driver 中指定代码搜索路径。代码搜索路径告诉 Ray 在启动 Java worker 时从哪里加载 jar 包。在运行代码之前,您必须将 jar 文件分发到 Ray 集群所有节点上的相同路径。

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

The /path/to/jars/ points to a directory which contains jars. Workers load all jars in the directory. You can also provide multiple directories for this parameter.

$ 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>

/path/to/jars/ 指向一个包含 jar 包的目录。Worker 会加载该目录中的所有 jar 包。您也可以为该参数提供多个目录。

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

注意

有关更多信息,请参阅Driver 选项下的 ray.job.code-search-path

目前,在单机模式下运行 Java 应用时无法配置 Ray。如果需要配置 Ray,请先运行 ray start 启动 Ray 集群。

Driver 选项#

Java drivers 有一组有限的选项。这些选项不是用于配置 Ray 集群,而仅用于配置 driver。

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

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

注意

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

通过系统属性配置的选项优先级高于配置文件中配置的选项。

  • 可用的 driver 选项列表

    • ray.address

    • 如果 driver 连接到现有的 Ray 集群,则为集群地址。如果为空,Ray 会创建一个新的 Ray 集群。

    • 类型:String

  • 默认值:空字符串。

    • ray.job.code-search-path

    • 如果 driver 连接到现有的 Ray 集群,则为集群地址。如果为空,Ray 会创建一个新的 Ray 集群。

    • 类型:String

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

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

    • ray.job.namespace

    • 如果 driver 连接到现有的 Ray 集群,则为集群地址。如果为空,Ray 会创建一个新的 Ray 集群。

    • 此 job 的命名空间。Ray 使用它来实现 job 之间的隔离。不同命名空间中的 job 无法相互访问。如果未指定,Ray 会使用一个随机值。