Skip to content

实验 5:调试和反模式

Ray 的 API 很容易上手,但性能问题经常来自错误的使用方式。本章列出最常见的几个坑。

反模式 1:循环里 ray.get

运行:

bash
uv run python examples/ray_demos/05_antipatterns.py

慢写法:

python
results = []
for i in range(8):
    results.append(ray.get(work.remote(i)))

快写法:

python
refs = [work.remote(i) for i in range(8)]
results = ray.get(refs)

原因:慢写法每次只允许一个任务在执行,破坏了并行性。

反模式 2:任务太细

不要把极小函数拆成 Ray Task:

python
@ray.remote
def add_one(x):
    return x + 1

如果每个任务只运行几微秒,调度和序列化开销会超过计算本身。

解决方式:

  • batch 多个元素。
  • 使用向量化库。
  • 用 Ray Data 做数据处理。

反模式 3:重复传大对象

慢:

python
refs = [predict.remote(model_weights, batch) for batch in batches]

更好:

python
weights_ref = ray.put(model_weights)
refs = [predict.remote(weights_ref, batch) for batch in batches]

如果模型要长期驻留在 GPU 上,Actor 可能更好:

python
worker = ModelWorker.remote(model_path)
refs = [worker.predict.remote(batch) for batch in batches]

反模式 4:单个 Actor 承担所有流量

Actor 默认串行执行。如果所有请求都发给一个 Actor,很容易排队。

解决方式:

  • 创建 Actor pool。
  • 按 key 分片。
  • 使用 async Actor。
  • 把无状态部分改成 Task。

反模式 5:资源声明缺失

GPU 任务必须声明 GPU:

python
@ray.remote(num_gpus=1)
def train(...):
    ...

否则 Ray 可能把多个 GPU 任务调度到同一块 GPU 所在节点,或者把任务调度到没有 GPU 的节点。

Dashboard 调试清单

启动 Ray 程序后,打开 Dashboard。你重点看:

页面关注点
JobsDriver 是否正常,任务是否失败
Tasks任务是否 pending、running、failed
ActorsActor 是否重启、队列是否堆积
NodesCPU/GPU 资源是否空闲或耗尽
ObjectsObject Store 是否接近满,是否 spill
LogsWorker、Raylet、GCS 错误

一套排查顺序

Mini Ray 调试

Mini Ray 提供 ray.metrics()

python
print(ray.metrics())

输出包含:

  • 提交任务数。
  • 完成任务数。
  • 失败任务数。
  • 当前对象数。
  • 资源总量和可用量。
  • Actor 数量。

这不是生产级监控,但足以帮助你理解运行时状态。

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