Skip to content

容错与可观测性

分布式程序一定会遇到失败:节点挂了、任务抛异常了、对象丢失了。Ray 在这里要做两件事:把失败以可理解的方式暴露出来,并在部分场景下自动恢复。

任务失败

远程任务抛异常时,异常不会在 .remote() 时出现,而是在 ray.get 时出现。

python
@ray.remote
def parse(line):
    raise ValueError("bad line")

ref = parse.remote("...")
ray.get(ref)  # RayTaskError

这是因为 .remote() 只提交任务,任务可能还没开始执行。

重试

Ray Task 可以配置重试:

python
@ray.remote(max_retries=3)
def flaky():
    ...

适合重试的错误:

  • 临时网络抖动。
  • 外部服务偶发失败。
  • 节点异常导致任务没完成。

不适合盲目重试的错误:

  • 输入数据格式错误。
  • 代码逻辑错误。
  • 不可重复执行的副作用任务。

副作用任务

如果任务会写数据库、扣库存、发消息,重试可能导致重复副作用。此时需要幂等设计或业务级去重。

Actor 失败

Actor 持有状态,所以 Actor 失败比 Task 失败复杂。

你需要考虑:

  • Actor 是否可以重启。
  • 状态如何恢复。
  • 已排队方法如何处理。
  • 调用方是否能重试。

Actor 可以配置 max_restartsmax_task_retries 等策略,但业务状态恢复仍然需要你设计。

对象丢失与 lineage

Ray 可以通过任务 lineage 知道某些对象是由哪个任务生成的。当对象丢失时,理论上可以重新执行生成它的任务。

这个机制的前提是任务可重放。如果任务依赖不可重复的外部副作用,重建结果就不可靠。

GCS 容错

现代 Ray 中 GCS 是集群元数据核心组件,官方文档提供了 GCS fault tolerance 配置。生产环境要关注:

  • GCS 是否配置持久化。
  • Head Node 故障后如何恢复。
  • Kubernetes 上的 RayCluster 生命周期。
  • Dashboard 和 State API 是否可用。

可观测性工具

Ray 提供多种观察入口:

工具用途
Dashboard查看节点、任务、Actor、对象、日志和指标
State API / CLI程序化查询任务、Actor、对象状态
日志目录查看 Worker、Raylet、GCS 日志
Metrics接入 Prometheus/Grafana
Timeline / profiling定位性能瓶颈

调试思路

遇到 Ray 程序慢或卡住时,按这个顺序查:

  1. 任务是否真的并行提交,还是在循环里 ray.get
  2. 资源是否足够,是否有任务等待 GPU 或自定义资源。
  3. 是否有大对象反复复制或 spill。
  4. Actor 队列是否堆积。
  5. Worker 日志是否有异常。
  6. 节点是否掉线或内存压力过大。

Mini Ray 的故障模型

Mini Ray 只做最小异常传播:

  • Task 抛异常时,ObjectStore 记录异常。
  • ray.get(ref) 时抛出 MiniRayTaskError
  • Actor 初始化失败时,后续方法调用也失败。

运行:

bash
uv run python examples/mini_ray_runtime/demos/06_failures.py

你会看到远程异常被包装后再传回 Driver。这和真实 Ray 的错误传播语义一致,只是没有自动重试和分布式恢复。

工程建议

  • 任务函数尽量纯,方便重试。
  • 外部副作用要幂等。
  • 大状态放 Actor 前先想清楚恢复策略。
  • 生产环境必须打开 Dashboard、日志采集和指标采集。
  • 不要把所有错误都交给 max_retries,它不是业务正确性的替代品。

面向学习目的的 Ray Core 中文导读与 Mini Ray 机制预览。