配置 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 stop 和 ray 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.sh 和 gencert_worker.sh。这些脚本为每个部署中的 head 和 worker Pod 的 initContainer 生成私钥和自签名证书文件(tls.key 和 tls.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字符串值。