Chapter 9

Failure Dection

为了让系统能够以适当的方式来处理各种故障,我们需要及时的发现故障。如果一个出错的处理器在他无法回复响应的情况下仍能够与其他处理器建立连接,他会加大系统的延迟并降低整个系统的可用性。

要在异步的分布式系统 (比如没有对任何时序做出假设) 中检测出故障是非常困难的,因为正如我们在 FLP Impossibility 一节中所讨论的,我们没办法确认处理器是已经崩溃、或是执行的异常缓慢跟不确定响应所需的时间。

术语如 dead 停止、failed 失效跟 crashed 崩溃通常会用来描述已经完全停止执行的处理器。术语如 unresonsive 无响应、faulty 出错的跟 slow 缓慢通常会用来描述那些可能已经崩溃的处理器。

故障可能会发生在连接的级别 (消息可能会在处理器间丢失或很久才能送达),或者在处理器的级别 (处理器可能崩溃了或执行的很缓慢),而缓慢并不总是意味着故障。这意味着需要为下列的情况中做出权衡,如错误的将仍然存活的处理器判断为故障 (因此产生了 正向的 False),如延迟将没有响应的处理器标记为故障,并期望他能够马上产生响应来得到这个猜测的益处 (产生了负向的 False)

错误检测器是一个本地负责对故障、无法触达的处理器进行标识的子系统,通过他来将这些处理器从算法中移除跟保证标识为安全节点的存活性。

存活性跟安全性是描述算法用来解决特定问题跟确保输出结果正确性的属性。更正式的说,存活性用来保证某些指定的事件必须发生。比如有一个处理器发生了故障,故障检查器则必须检查到这个故障。安全性保证了不会发生意料之外的事件,比如错误检查器将一个处理器标识为崩溃了,这个处理器事实上必须就是崩溃的。

从更实际的视角来看,移除那些故障的处理器有助于避免不必要的工作跟防止了因为错误传播而产生的级联问题。排除潜在的可能还存活的处理器会导致整体的可用性。

错误检测算法需要体现几个必须的基础属性。首先,所有未出错的成员最终需要能够察觉到故障的处理器,并且算法要能够持续执行并最终得到最后的结果。这个属性称为 Completeness 完整性。

我们可以通过算法的 Efficiency 高效来判断其质量:错误监测器能够多快的表示出故障的节点。另一个方式是通过观察算法的准确度:处理器的故障能否被精确的检测到。换句话说,一个不精准的算法会错误的将存活的处理器标识为崩溃或没办法检测出已经发生的故障。

我们可以将高效性跟精准性当成两个互相关联的参数:具有更高性能的可能会具有更低的准确度,而具有更高精确度的算法通常会不那么高效。事实上要构建一个同时具备了高性能跟高精确度的故障检测器几乎是不可能的。与此同时,错误监测器允许发生正向的 False 检测。(如错误的将仍然存活的处理器标识为失效)

故障监测器对于我们将在本书中所讨论的共识跟原子广播算法是一个必要的部分。

许多的分布式系统都使用了 heartbeats 心跳来实现错误检测,这种方式流行的原因是因为他较为简单并且具有较强的完整性。我们在这里讨论的算法都假设不存在拜占庭故障:处理器并不会尝试在自身的状态上去欺骗其他的处理器。