调试失败#
Ray 中存在哪些类型的失败?#
Ray 由两个主要的 API 组成:用于创建 Task 或 Actor 的 `.remote()`,以及用于获取结果的 ray.get。调试 Ray 意味着识别和修复由 `.remote` API 创建的函数和类(Tasks 和 Actors)运行的远程进程中的失败。
Ray API 是 Future API(实际上,可以将 Ray 对象引用转换为标准的 Python Future API),错误处理模型也是如此。当任何远程 Tasks 或 Actors 失败时,返回的对象引用会包含一个异常。当您对对象引用调用 `get` API 时,它会引发一个异常。
import ray
@ray.remote
def f():
raise ValueError("it's an application error")
# Raises a ValueError.
try:
ray.get(f.remote())
except ValueError as e:
print(e)
...
ValueError: it's an application error
在 Ray 中,存在三种类型的失败。有关更多详细信息,请参阅异常 API。
应用程序失败:这意味着远程任务/Actor 因用户代码而失败。在这种情况下,`get` API 将引发
RayTaskError,其中包含从远程进程引发的异常。故意系统失败:这意味着 Ray 失败了,但这是故意的。例如,当您调用取消 API(如任务的 `ray.cancel` 或 Actor 的 `ray.kill`)时,系统会失败远程任务和 Actor,但这属于故意行为。
意外系统失败:这意味着远程任务和 Actor 由于意外的系统故障而失败,例如进程崩溃(例如,由于内存不足错误)或节点故障。
Linux Out of Memory killer 或 Ray Memory Monitor 会终止内存使用量高的进程,以避免内存不足。
机器关闭(例如,抢占式实例终止)或 Raylet 崩溃(例如,由于意外故障)。
系统高度过载或压力过大(无论是机器还是系统组件,如 Raylet 或 GCS),这会导致系统不稳定并发生故障。
调试应用程序失败#
Ray 将用户的代码分发到许多机器上的多个进程中。应用程序失败意味着用户代码中存在错误。Ray 提供了与调试单进程 Python 程序类似的调试体验。
print#
`print` 调试是调试 Python 程序最常见的方法之一。Ray 的 Task 和 Actor 日志默认打印到 Ray Driver,这允许您直接使用 `print` 函数来调试应用程序失败。
调试器#
许多 Python 开发人员使用调试器来调试 Python 程序,而 Python pdb 是其中一种流行的选择。Ray 与 `pdb` 具有原生集成。您可以简单地在 Actor 和 Task 代码中添加 `breakpoint()` 来启用 `pdb`。有关更多详细信息,请参阅 Ray Debugger。
文件描述符耗尽(Too many open files)#
在 Ray 集群中,任意两个系统组件都可以相互通信并建立 1 个或多个连接。例如,一些 Worker 可能需要与 GCS 通信以调度 Actor(worker <-> GCS 连接)。您的 Driver 可以调用 Actor 方法(worker <-> worker 连接)。
Ray 可以支持数千个 Raylet 和数万个 Worker 进程。当 Ray 集群规模扩大时,每个组件可能拥有越来越多的网络连接,这需要文件描述符。
Linux 通常将每个进程的默认文件描述符限制为 1024。当组件的连接数超过 1024 时,可能会引发以下错误消息。
Too many open files
这对于 Head 节点 GCS 进程尤其常见,因为它是一个集中的组件,Ray 中许多其他组件都与它通信。当您看到此错误消息时,我们建议您通过 `ulimit` 命令调整每个进程的最大文件描述符限制。
我们建议您在主机配置中应用 `ulimit -n 65536`。但是,您也可以选择性地将其应用于 Ray 组件(参见下面的示例)。通常,每个 Worker 有 2-3 个到 GCS 的连接。每个 Raylet 有 1-2 个到 GCS 的连接。65536 个文件描述符可以处理 10000-15000 个 Worker 和 1000-2000 个节点。如果您有更多 Worker,应考虑使用大于 65536 的数字。
# Start head node components with higher ulimit.
ulimit -n 65536 ray start --head
# Start worker node components with higher ulimit.
ulimit -n 65536 ray start --address <head_node>
# Start a Ray driver with higher ulimit.
ulimit -n 65536 <python script>
如果无效,请通过运行 `ulimit -Hn` 再次检查硬限制是否足够大。如果太小,您可以通过以下方式增加硬限制(这些说明适用于 EC2)。
通过运行以下命令,系统范围地增加打开文件描述符的硬 ulimit。
sudo bash -c "echo $USER hard nofile 65536 >> /etc/security/limits.conf"
注销并重新登录。
内存问题导致的失败#
有关更多详细信息,请参阅 调试内存问题。
本文档讨论了人们在使用 Ray 时遇到的一些常见问题以及一些已知问题。如果您遇到其他问题,请告诉我们。