Ray集群无法在各节点均匀分配Worker导致头节点内存溢出崩溃
Ray集群单节点调度过载问题排查方案
问题背景
3台12CPU的私有化部署机器搭建Ray集群,单Actor分配1CPU,手动启动头节点和工作节点后,所有Worker持续被调度到头节点导致头节点内存耗尽崩溃,其余工作节点无调度负载。
头节点启动命令参考:
ray start --head --port=... --redis-shard-ports=... --node-manager-port=... --object-manager-port=... --min-worker-port=... --max-worker-port=... --ray-client-server-port=... --gcs-server-port=... --num-cpus=12
工作节点启动命令参考:
ray start --address='<HEAD_IP>' --redis-password='...' --node-manager-port=... --object-manager-port=... --min-worker-port=... --max-worker-port=... --dashboard-port=... --gcs-server-port=... --num-cpus=12
排查解决步骤
按以下顺序逐一排查,绝大多数场景下前3步就能定位问题:
1. 确认工作节点是否真正接入集群
很多时候工作节点启动命令执行完无报错,但实际没有成功注册到集群,自然不会被分配任务:
- 头节点执行
ray status命令,查看输出的节点列表:- 如果总CPU数只有12,说明工作节点完全没接入,优先排查网络连通性:确认头节点和工作节点之间手动指定的所有端口(GCS端口、节点管理端口、对象管理端口、worker端口范围)没有被防火墙拦截,工作节点填写的头节点IP是内网可达的真实IP,禁止填127.0.0.1这类回环地址。
- 检查工作节点
/tmp/ray/session_latest/logs/路径下的raylet.out、gcs_server.out日志,排查是否存在连接拒绝、密码错误、版本不匹配的报错,这类问题都会直接导致节点注册失败。 - 执行
ray --version核对3台机器的Ray版本,注意:所有节点的Ray版本必须完全一致,哪怕是小版本差异都可能导致节点注册异常、无法接收任务。
- 如果
ray status能看到3个节点IP,但工作节点的可用CPU显示为0,先在对应工作节点执行ray stop --force清理残留进程,再重新执行启动命令。
2. 修正头节点资源配置
当前头节点启动参数中--num-cpus=12的配置,等于把所有CPU资源全开放给Worker调度,但头节点本身要运行GCS、Raylet、对象存储等核心管理进程,这些进程和Worker抢资源时很容易触发调度异常:
- 调整头节点启动参数,给管理进程预留2核左右资源,把
--num-cpus=12改成--num-cpus=10。 - 所有节点启动时显式指定可用内存,不要用系统自动检测的数值:比如机器总内存64G的话,加参数
--memory=50000000000(单位为字节),留10G以上给系统和管理进程;同时加--object-store-memory=10737418240给对象存储固定分配10G内存,避免对象存储无限制占用内存触发OOM。
3. 调整调度策略避免单节点堆积
老版本Ray默认的bin-pack调度策略会优先往已有负载的节点塞任务,直到节点资源耗尽才会调度到其他节点,由于Worker单进程内存占用高,很容易出现CPU还没占满、内存先耗尽的情况:
- 全局开启分散调度:代码里初始化Ray连接时指定策略,示例:
import ray ray.init(address="auto", scheduling_strategy="SPREAD") - 如果不想修改全局策略,也可以单独给高内存的Actor指定分散调度,在Actor装饰器加参数即可:
@ray.remote(num_cpus=1, scheduling_strategy="SPREAD") class YourActor: pass
4. 排查错误的调度约束
如果前面的配置都没问题,检查代码里是否误加了调度限制:
- 有没有给Actor指定只有头节点才有的自定义资源,比如调试时加的节点标签、特殊资源约束,工作节点没有对应标签的话,任务只会调度到头节点。
- 有没有残留硬编码的节点指定逻辑,比如
resources={"node:<头节点IP>": 0.01}这类强制指定节点运行的配置,调试结束后忘记删除。
5. 优化内存检测阈值避免崩溃
所有节点启动时加以下参数,提高内存异常响应速度,避免内存耗尽直接崩溃:
--memory-monitor-interval-ms=100 --raylet-death-on-oom=false
参数作用是把内存检测间隔缩短到100ms,内存达到阈值时优先触发任务迁移、对象驱逐,不会等内存完全耗尽导致raylet进程直接崩溃。
内容的提问来源于stack exchange,提问作者andrew
相关产品推荐
相关产品推荐

