发起 Ray 分布式训练
Ray 是一个用于构建和运行分布式应用的通用计算框架,提供统一的 Python 原语(任务、Actor、Placement Group)与高层库(Train/Tune/Serve/Data),让您在多机多卡场景下高效调度资源。
我们的平台为 Ray 用户提供开箱即用的分布式计算环境:无需手工启动 Head/Worker、无需维护集群与版本、无需关心镜像预热与节点就绪。用户只需提供入口命令(entrypoint)与依赖定义,平台会自动创建并管理 Ray 集群,完成节点检查、资源调度、日志与指标采集,并提供 Dashboard 入口与故障自愈功能,让训练、数据处理与推理任务更稳定、更可观测。
与本地 Ray 的关键差异
本平台保持原生 Ray API 的使用方式不变,但在作业提交流程、集群管理方式与资源调度模型上与本地/物理机环境存在一些重要差异。
集群由平台托管,无需手工启动:无需再执行
ray start或ray job submit或管理节点 IP。在平台上,您提交的是整份 Ray 作业,平台在 Kubernetes 上托管 Head/Worker 的创建、重试与回收。启动命令(entrypoint)会在 Head 节点内作为 Driver 启动,集群规模固定(当前不支持 autoscaler):平台当前暂不支持 Ray Autoscaler。Head 与 Worker 数量会在提交表单时确定,并在作业生命周期内保持固定。因此,训练并行度、数据分片方式、Placement Group 大小等策略,需要与您提交时指定的 Worker 数一致规划。
平台统一进行节点就绪与健康检查:平台在作业启动阶段会自动等待 Worker 数量达标,使用内置的 Ray API 检查脚本确保所有节点成功加入集群后才执行您的入口脚本。您无需在代码中轮询
ray.nodes()或添加额外等待逻辑;若节点未能在超时时间内就绪,平台会给出明确的错误并按策略重试。运行环境 = 容器镜像 + runtimeEnv:平台的 Ray 环境由镜像与 runtimeEnv 共同决定:
- 镜像决定 Ray、Python、CUDA、NCCL 等基础组件版本
runtimeEnv用于 pip/conda 依赖、working_dir、py_modules、环境变量等用户层内容
注意
runtimeEnv不用于设置节点级系统参数(如 object store 大小、端口、内核参数)。这类设置需通过任务页面的「环境变量」配置完成。- 任务支持从网页界面填写环境变量,并注入 Ray 作业环境中。在创建任务、编辑任务时可在页面找到环境变量一栏。通过网页注入的环境变量将与
runtimeEnv,如有重复,优先级低于runtimeEnv中定义的值。
资源声明与调度由平台负责:在提交 Ray 作业时,您需要为 Head/Worker 声明算力规格(规格包含了 CPU、GPU、内存、共享内存(/dev/shm)等配置)。平台会负责调度、隔离与派发。Ray 中的
num_gpus、num_cpus表示 Worker 可分配的容器级资源,而非物理节点级资源。Ray 任务对象存储内存(object_store_memory) 默认为 Ray 集群所有规格总内存的 30%。网络与可观测性由平台统一暴露:平台会为 Ray Dashboard 提供访问入口(带访问控制),无需管理端口或 Service。任务日志还统一聚合 Driver/Worker 的标准输出日志与事件,并提供节点登录和诊断能力(如容错日志、atcctl 工具)帮助用户排障。
数据与持久化方式与本地环境不同:容器的本地磁盘会在作业结束后被回收,因此本地路径适合临时数据。训练数据、checkpoint、模型权重等建议使用高性能共享存储,以便失败恢复与跨作业复用。
基本流程
在 AIStudio 任务中,通过以下步骤启动 Ray 分布式训练任务:
- 创建训练任务:配置任务 Worker 规格、Worker 数量,设置「分布式框架」为 Ray。
- 填写启动命令/
- 初始化:平台创建对应的 pod,并注入必要环境变量,供用户代码获取环境信息。
- 容错检查:训练开始前,平台发起自检,确保所有 Worker 之间网络通畅、GPU、存储工作正常。
- 训练执行:
- 若任意 pod 失败(退出码非 0),训练任务失败。
- 若所有 pod 成功完成(退出码为 0),训练任务成功。
Ray 任务示例
使用 Ray 官方的分布式超参数搜索示例 mnist_pytorch.py,使用 Pytorch 和 Ray Tune,在 MNIST 数据集上进行参数的搜索。
遵循上述基础流程,在网页提交训练任务。本示例使用自定义镜像,其中已安装
ray[default]与ray[tune]等关键依赖,并以封装测试脚本/workspace/mnist_pytorch.py。在填写 Bash 启动命令时,无需
ray start或ray job submit,只需要提供入口命令(例如python /workspace/mnist_pytorch.py --cuda);平台在 head 内启动 Driver,并自动注入 RAY_ADDRESS、runtime env 与资源配置。功能上等同于一次作业提交,但无需显式调用 CLI。shellpython /workspace/mnist_pytorch.py --cuda
日志与诊断
- 在任务运行过程中,可前往任务详情页,切换到「任务日志」标签,可分别查看 head 节点、worker 节点的日志。
- 在任务运行过程中,可前往任务详情页,切换到「详情」标签:
- 在任务详情页顶部,可看到 Ray Dashboard 超链接。Dashboard 的可见内容与可执行操作可能受平台控制;任务的 Ray Dashboard 访问需要通过平台账号鉴权。
- 如果开启了「任务可视化」并填写了正确的日志路径,可访问 Tensorboard 可视化面板。
- 在任务详情页底部,可看到 Worker 列表和登录按钮。可从网页端登录任务 Worker,访问 Web Terminal。
- 在任务运行过程中,可前往任务详情页,切换到「详情」标签,在任务详情页底部可看到 Worker 列表和登录按钮。可从网页端登录任务 Worker,访问 Web Terminal。
- 任务功能提供 atlctl 命令行调试工具,您可以从 Web Terminal 登录任意的任务 Worker,执行停止任务、统一下发测试命令等调试工作。
常见问题
我还需要在代码里写 ray start 或 ray job submit 吗?
不需要。
在平台上提交 Ray 作业时:
- 平台会在 Head 节点 容器内自动执行
ray start --head ...启动 Ray 集群; - 在 Worker 节点 容器内自动执行
ray start --address=<head-service>:6379 --block将 Worker 加入集群; - 平台使用内置脚本,通过 Ray Client 地址(例如
ray://127.0.0.1:10001)做健康检查,确保集群节点数达标后才启动您的入口脚本。
您的训练脚本只需要作为 Driver 在 Head 内运行,无需再手动调用 ray start 或 ray job submit。
在平台上我应该写 ray.init() 还是 ray.init(address="...")?
在 python 脚本中,通常只需要:
import ray
ray.init() # 或 ray.init(address="auto")即可。
原因是:
- Head 节点容器内 Ray 集群已经由平台预先启动,Ray 自己的提示也是「直接 ray.init() 即可连接本地集群」;
- 平台负责管理集群的具体地址与端口(例如
ray://127.0.0.1:10001、<task-id>-ray-head:6379),您的脚本不需要硬编码这些内部地址。
只有在您有非常特殊的调试需求时,才建议显式指定 address,一般训练任务不需要。
一个平台任务会创建几个 Ray 集群?集群什么时候销毁?
- 一个任务 = 一个 Ray 集群。
每次提交 Ray 任务,平台都会为这次任务在 Kubernetes 上创建一套 Head / Worker,构成一个独立的 Ray 集群。 - 任务结束 = 集群销毁。
当任务执行完成(无论成功还是失败),对应的 Ray 集群和 Pod 会被回收,容器本地文件系统也会被清空。
如果您需要多次实验或多次训练,可以复用同一个任务配置重复提交,每次提交都会获得一个新的 Ray 集群生命周期。
Head 和 Worker 的规格可以不同吗?
当前不支持。
- 在任务配置中选择的算力规格(CPU / GPU / 内存 / 共享内存等),会同时用于 Head 和 所有 Worker;
- 不支持「CPU-only Head + GPU Worker」或「大 Head + 小 Worker」这类异构拓扑。
如果您确实需要异构资源(例如单独的预处理集群 + 训练集群),建议拆成多个任务,分别配置不同的规格。
任务中有哪些对分布式训练有用的环境变量?
平台会在容器中注入一批与分布式相关的环境变量,典型包括(以示例为准,可能会按版本调整):
WORLD_SIZE:本次作业中参与分布式训练的总进程数;RANK:当前进程的全局 rank;MASTER_ADDR:主进程(通常在 Head)监听的地址,例如jo-xxxx-head-0;MASTER_PORT:主进程监听端口,例如29500;NCCL_SOCKET_IFNAME/GLOO_SOCKET_IFNAME:NCCL / Gloo 使用的网卡名(如eth0),用于避免多网卡场景下的连接问题;NVIDIA_VISIBLE_DEVICES:当前容器可见的 GPU 数量,与NVIDIA_VISIBLE_DEVICES一起约束可用设备;CUDA_VERSION、NCCL_VERSION以及一系列NV_*变量:标示当前镜像内 CUDA/cuDNN/NCCL 的版本信息。
您可以在代码中直接消费这些变量,例如:
- 使用 PyTorch DDP 时,将
MASTER_ADDR、MASTER_PORT、WORLD_SIZE、RANK传给torch.distributed.init_process_group; - 根据
NVIDIA_VISIBLE_DEVICES选择当前进程应绑定的 GPU。
Ray 本身的启动与集群加入逻辑由平台托管,一般不需要您再去修改这些变量。
容器里的本地路径(如 /tmp、/root、/workspace)适合放哪些数据?任务结束后还在吗?
- 容器本地文件系统适合存放 临时数据:
- 中间结果、cache、临时日志等;
- 当任务结束时,Ray 集群和对应的 Pod 会被销毁,本地数据不会保留。
对于需要跨任务复用或在失败后恢复的内容(训练数据、checkpoint、模型权重等),建议统一写入平台提供的高性能共享存储(详见存储文档),而不是只写在容器本地。
我可以在同一个任务里再启动一个独立的 Ray 集群吗?
不推荐,也基本没有必要。
- 平台已经为每个任务创建并托管一个 Ray 集群;
- 不支持在任务内部再通过 Ray Autoscaler config 额外启动物理集群,会与平台的生命周期管理和调度模型冲突。
推荐模式是:
- 每个需要独立生命周期和资源配额的 Ray 作业,都作为一个平台任务提交;
- 不在任务内部再创建额外的 Ray 集群。