故障与部分失效
在分布式系统中,尽管系统的其他部分⼯作正常,但系统的某些部分可能会以某种不可预知的⽅式被破坏。这被称为部分失效(partial failure)。难点在于部分失效是不确定性的(nonderterministic):如果你试图做任何涉及多个节点和⽹络的事情,它有时可能会⼯作,有时会出现不可预知的失败。正如我们将要看到的,你甚⾄不知道是否成功了,因为消息通过⽹络传播的时间也是不确定的!
云计算与超级计算机
不可靠的网络
- 请求可能已经丢失(可能有⼈拔掉了⽹线)。
- 请求可能正在排队,稍后将交付(也许⽹络或收件⼈超载)。
- 远程节点可能已经失效(可能是崩溃或关机)。
- 远程节点可能暂时停⽌了响应(可能会遇到⻓时间的垃圾回收暂停;参阅“暂停进程”),但稍后会再次响应。
- 远程节点可能已经处理了请求,但是⽹络上的响应已经丢失(可能是⽹络交换机配置错误)。
- 远程节点可能已经处理了请求,但是响应已经被延迟,并且稍后将被传递(可能是⽹络或者你⾃⼰的机器过载)。
真实世界的网络故障
处理⽹络故障并不意味着容忍它们:如果你的⽹络通常是相当可靠的,⼀个有效的⽅法可能是当你的⽹络遇到问题时,简单地向⽤户显示⼀条错误信息。但是,您确实需要知道您的软件如何应对⽹络问题,并确保系统能够从中恢复。有意识地触发⽹络问题并测试系统响应(这是Chaos Monkey背后的想法;参阅“可靠性”)。
检测故障
关于远程节点关闭的快速反馈很有⽤,但是你不能指望它。即使TCP确认已经传送了⼀个数据包,应⽤程序在处理之前可能已经崩溃。如果你想确保⼀个请求是成功的,你需要应⽤程序本身的积极响应【24】。相反,如果出了什么问题,你可能会在堆栈的某个层次上得到⼀个错误响应,但总的来说,你必须假设你根本就没有得到任何回应。您可以重试⼏次(TCP重试是透明的,但是您也可以在应⽤程序级别重试),等待超时过期,并且如果在超时时间内没有收到响应,则最终声明节点已经死亡。
超时与无穷的延迟
不幸的是,我们所使⽤的⼤多数系统都没有这些保证:异步⽹络具有⽆限的延迟(即尽可能快地传送数据包,但数据包到达可能需要的时间没有上限),并且⼤多数服务器实现并不能保证它们可以在⼀定的最⼤时间内处理请求(请参阅“响应时间保证”)。对于故障检测,系统⼤部分时间快速运⾏是不够的:如果你的超时时间很短,往返时间只需要⼀个瞬时尖峰就可以使系统失衡。
网络拥塞和排队
同步网络 vs 异步网络
不可靠的时钟
⽽且,⽹络上的每台机器都有⾃⼰的时钟,这是⼀个实际的硬件设备:通常是⽯英晶体振荡器。这些设备不是完全准确的,所以每台机器都有⾃⼰的时间概念,可能⽐其他机器稍快或更慢。可以在⼀定程度上同步时钟:最常⽤的机制是⽹络时间协议(NTP),它允许根据⼀组服务器报告的时间来调整计算机时钟【37】。服务器则从更精确的时间源(如GPS接收机)获取时间。
单调钟与时钟
时钟
单调钟
时钟同步与准确性
如果你⾜够关⼼这件事并投⼊⼤量资源,就可以达到⾮常好的时钟精度。例如,针对⾦融机构的欧洲法规草案MiFID II要求所有⾼频率交易基⾦在UTC时间100微秒内同步时钟,以便调试“闪崩”等市场异常现象,并帮助检测市场操纵 【51】。使⽤GPS接收机,精确时间协议(PTP)【52】以及仔细的部署和监测可以实现这种精确度。然⽽,这需要很多努⼒和专业知识,⽽且有很多东⻄都会导致时钟同步错误。如果你的NTP守护进程配置错误,或者防⽕墙阻⽌了NTP通信,由漂移引起的时钟误差可能很快就会变⼤。
依赖同步时钟
有序事件的时间戳
时钟读数存在置信区间
⼀个有趣的例外是Spanner中的Google TrueTime API 【41】,它明确地报告了本地时钟的置信区间。当你询问当前时间时,你会得到两个值:[最早,最晚],这是最早可能的时间戳和最晚可能的时间戳。在不确定性估计的基础上,时钟知道当前的实际时间落在该区间内。间隔的宽度取决于⾃从本地⽯英钟最后与更精确的时钟源同步以来已经过了多⻓时间。