旧游无处不堪寻
无寻处,惟有少年心
『数据密集型应用系统设计』读书笔记(八)

分布式系统与在单节点上的软件有着非常显著的区别,你会碰到五花八门、千奇百怪的问题所导致的各种故障。本章我们将了解这些实践中所出现的问题,充分认识眼前的挑战。

作为开发者,我们的核心任务是构建可靠的系统,即使系统面临各种出错可能,也需要完成预定工作。本章对分布式系统可能出现的故障做了一个全面、近乎悲观的总结。

故障与部分失效


在单节点上开发程序时,通常它应该以一种确定性的方式运行: 要么正常运行,要么出错。有 bug 的软件可能最终会在某天暴露出来,单台节点上的软件通常不会也不应该出现模棱两可的现象。

但是对于这种分布式系统,理想化的标准正确模型不再适用。在分布式系统中,可能会出现系统的一部分工作正常,但其他某些部分出现难以预测的故障,我们称之为部分失效

正是由于这种不确定性和部分失效大大提高了分布式系统的复杂性。

不能假定故障不可能发生而总是期待理想情况。最好仔细考虑各种可能的出错情况,包括那些小概率故障,然后尝试人为构造这种测试场景来充分检测系统行为。

不可靠的网络


我们假定网络是跨节点通信的唯一途径,并且每台机器都有自己的内存和磁盘,一台机器不能直接访问另一台机器的内存或磁盘除非通过网络向对方发出请求。
需要注意: 无共享并不是构建集群系统的唯一方式,但它却是构建互联网服务的主流方式。

直观来看,系统的可靠性应该取决于最不可靠的组件。然而,对于计算机系统来讲,事实并非如此,在低可靠性部件上构建高可靠的系统一直是计算机领域的惯用手段:

  1. 纠错码可以在各种通信链路上准确传输数据
  2. IP 层本身并不可靠,可能会出现丢包、延迟、重复发送以及乱序等情况。但 TCP 在 IP 之上提供了更可靠的传输层,可以保证丢失的数据包被重传,消除重复包,包的顺序以发送的顺序重新组合等

互联网以及大多数数据中心的内部网络都是异步网络。发送之后等待响应过程中,有很多事情可能会出错:

  1. 请求可能已经丢失
  2. 请求可能正在某个队列中等待,无法马上发送
  3. 远程接收节点可能已经失效
  4. 远程接收节点可能暂时无法响应
  5. 远程接收节点已经完成了请求处理,但回复却在网络中丢失
  6. 远程接收节点已经完成了请求处理,但回复却被延迟处理

处理这个问题通常采用超时机制: 在等待一段时间之后,如果仍然没有收到回复则选择放弃,并且认为响应不会到达。

处理网络故障并不意味着总是需要复杂的容错措施: 假定你的网络通常非常可靠,而万一出现问题,一种简单的方法是对用户提示错误信息。但前提是,必须非常清楚接下来软件会如何应对,以确保系统最终可以恢复。

我们推荐有计划地人为触发网络问题,目的是测试系统的反应情况。

不可靠的时钟


在分布式系统中,时间总是件棘手的问题,由于跨节点通信不可能即时完成,消息经由网络从一台机器到另一台机器总是需要花费时间。 收到消息的时间应该晚于发送的时间,但是由于网络的不确定延迟,精确测量面临着很多挑战。
而且,网络上的每台机器都有自己的时钟硬件设备,通常是石英晶体振荡器。这些设备并非绝对准确,即每台机器都维护自己本地的时间版本。
可以在一定程度上同步机器之间的时钟,最常用的方法是网络时间协议(Network Time Protocol,NTP),它可以根据一组专门的时间服务器来调整本地时间,时间服务器则从精确更高的时间源获取高精度时间。

需要注意: 依靠精确的时钟存在一些风险,没有特别简单的办法来精确测量时钟的偏差范围。