之前几章都在谈系统如何处理出错:副本故障切换、副本数据滞后、事务的并发控制。但前几张考虑到的情况:机器宕机、网络延迟都相对较理想。在实际大型分布式系统中,情况会更为悲观,可能会出错组件的一定会出错,而且出错的方式会更为复杂。任何大型系统的运维人员想必对此都有深有体会。
构建分布式系统和单机软件完全不同。在分布式系统中,系统有一千种奇妙的出错方法,本章将会探讨其中的一部分。我们会发现,在单机中我们以为是无比自然的假设,在分布式系统中,都可能不成立。作为工程师,我们总期望能构建能够处理任何可能故障的系统,但在实践中,一切都是权衡。不过,我们首先需要知道,可能会遇到哪些问题,才能进而选择:是否要在目标场景下解决这些问题、还是为了降低系统复杂度忽略这些问题。
本章将会探讨计算机网络的痼疾、时钟和时间、以什么程度避免上述问题等等。所有上述问题的原因都隐藏的很深,本章会探索如何理解分布式系统当前所处状态、如何定位分布式系统问题原因所在。
在单机上编程,其行为通常可预测。如果程序运行有问题,通常不是计算机硬件的问题,一般是代码代码写的不够好。而且:
总结来说,单机系统通常具有一种很好地特性:要么正常运行、要么出错崩溃,而不会处于一种中间状态。这也是计算机的最初设计目标:始终正确的进行计算。
但在构建分布式系统时,系统行为边界变得模糊起来。在分布式系统中,有很多我们习以为常的假设都不复存在,各种各样的异常问题都会出现。其中最令人难受的是:部分失败(partial failure),即系统的一部分正常工作,另一部分却以某种诡异的方式出错。这些问题,多数都是由于连接不同主机的异步网络所引入的。
在构建大型计算系统的选择上一个光谱:
不同构建计算系统的哲学,有着不同的处理错误的方式。对于高性能计算(也称超算)来说,通常会定期将状态持久化到外存。如果其中一个节点出现故障,通常会停止整个集群负载。当节点故障修复后,从故障前的最近快照重新开始运行。可以看出,超算更像是单机系统而非分布式系统。
但在本章,我们将重点放到以网络连接的多机系统中,这样的系统与单机应用与诸多不同之处: