弹性

软件会发生故障,硬件会发生故障,网络连接会发生故障,用户代码也会发生故障。本文档描述了 dask.distributed 如何应对这些故障以及其他已知 bug。

用户代码故障

当函数引发错误时,该错误会被保留并在请求时传输给客户端。任何尝试获取该结果 或任何依赖结果 的操作都将引发该异常。

>>> def div(a, b):
...     return a / b

>>> x = client.submit(div, 1, 0)
>>> x.result()
ZeroDivisionError: division by zero

>>> y = client.submit(add, x, 10)
>>> y.result()  # same error as above
ZeroDivisionError: division by zero

这不会以任何方式影响调度器或 Worker 的平稳运行。

网络连接关闭

如果与远程 Worker 的连接意外关闭,且本地进程适当地引发了 IOError,则调度器会将所有待处理的计算重新路由到其他 Worker。

如果丢失的 Worker 是唯一持有后续计算所需重要结果的 Worker,则这些结果将由幸存的 Worker 重新计算。调度器会维护每个结果是如何产生的完整历史记录,因此能够在其他 Worker 上重现相同的计算。

这存在一些失败情况。

  1. 如果结果依赖于非纯函数,则您可能会得到不同的结果(尽管仍然完全准确)

  2. 如果 Worker 因某个不良函数而失败,例如导致段错误的函数,则该不良函数将在其他 Worker 上重复调用。该函数在杀死固定数量的 Worker(默认为三个)后将被标记为“不良”。

  3. 通过调用 scatter() 直接发送给 Worker 的数据(而不是通过其他 Dask 函数从 Dask 任务图创建的数据)不会保存在调度器中,因为它通常非常大,因此丢失这些数据是无法弥补的。您可能希望对数据调用 replicate() 并设置合适的复制因子,以确保数据长期存在,或者将其备份到某个弹性存储(如文件系统)上。

硬件故障

目前尚不清楚在何种情况下本地进程会知道远程 Worker 已关闭连接。如果套接字未能正常关闭,系统将等待超时(大约三秒),然后将 Worker 标记为失败并恢复平稳运行。

调度器故障

包含调度器的进程可能会崩溃。目前没有持久化机制来记录和恢复调度器状态。

调度器重新上线后,Worker 和客户端都会重新连接,但正在进行的计算记录将会丢失。

重启和 Nanny 进程

客户端提供了一种机制来重启集群中的所有 Worker。如果在实验过程中发现 Worker 处于无响应的不便状态,这会很方便。Client.restart 方法会杀死所有 Worker,清除所有调度器状态,然后使所有 Worker 重新上线,从而得到一个干净的集群。这需要 nanny 进程(默认情况下会启动)。