分布式系统面临哪些挑战?
构建大型计算系统的方式:
超级计算机怎么处理故障?
互联网服务的系统与超级计算机系统的区别?
互联网服务的系统 | 超级计算机 |
---|---|
在线的,低延迟,不可重启 | 离线的,批处理,可以重启 |
普通硬件,较低成本,较高故障率 | 专用硬件,节点可靠,节点通过共享内存和远程直接内存访问(RDMA)进行通信 |
基于 IP 和以太网 | 专门的网络拓扑 |
故障频发,需要很快的处理故障 | 可以花较多的时间从错误中恢复 |
可以容忍发生故障的节点 | 不能容忍故障节点 |
地理位置分布发散,通信通过互联网,通信缓慢且不可靠 | 所有节点都靠近一起 |
构建分布式系统的思路?
网络可能出现的错误?
怎么处理网络错误?
为什么需要自动检测故障节点?
怎么判断一个节点是否工作?
超时应该得到多久?
过短的超时可以吗?
虚构的系统中,合理的超时时间?
实际上,大多数系统都没有这些保证。
计算机网络上数据包延迟的可变性通常是由于排队:
怎么解决多租户数据中心的网络拥塞问题?
为什么我们不能在硬件层面上解决这个问题,使网络可靠,使软件不必担心呢?
以非常可靠的传统固定电话网络为例:
时钟和时间很重要。应用程序以各种方式依赖于时钟来回答以下问题:
时钟为什么不可靠?
计算机至少有两种目的不一样的时钟:
日历时钟是什么?
缺点:
是什么?
怎么用?
会修改吗?
精确度?
在分布式系统中的作用?
举例:
时钟导致的问题:
处理方法:
最后写入胜利(LWW)
能不能用NTP 同步避免不正确的排序?
怎么避免时钟问题呢?
可以使用同步时钟的时间戳作为事务ID吗?
设想一个单领导者的分布式数据库,一个节点怎么知道自己仍然是领导者?
使用租约的问题在哪?
线程为什么会暂停很长时间?
线程暂停的后果?
如何做到在特定事件响应的保证?
怎么降低垃圾回收带来的影响?
何为真假?感知和测量不可靠,我们怎么确定信息的可靠性?这是个哲学问题。
真相到底是什么?
最常见的法定人数是超过一半的绝对多数(尽管其他类型的法定人数也是可能的)。
第九章将继续讨论共识算法。
通常,一些东西在一个系统中只能有一个。如:
分布式系统可能出现「唯一的节点」不止一个!
图8-4 分布式锁的实现不正确:客户端1认为它仍然具有有效的租约,即使它已经过期,从而破坏了存储中的文件
确保一个被误认为自己是「唯一的节点」,不能扰乱系统的其它部分。实现这一目标的一个相当简单的技术就是防护(fencing)。
图8-5 只允许以增加防护令牌的顺序进行写操作,从而保证存储安全
具体做法:
防护令牌需要注意?
防护令牌是缺点还是好事?
防护令牌一定可靠吗?
节点会撒谎吗?
什么情况下会出现拜占庭容错?
我的系统需要考虑拜占庭故障吗?
为什么一般不需要考虑拜占庭故障?
什么是弱谎言?
常见的弱谎言以及怎么处理?
分布式系统问题要求我们以某种方式将我们期望在系统中发生的错误形式化——模型。
关于时序假设,三种系统模型是常用的:
同步模型
部分同步模型
异步模型
除了时序问题,我们还要考虑节点失效。三种最常见的节点系统模型是:
崩溃-停止故障
崩溃-恢复故障
拜占庭(任意)故障
对于真实系统的建模,具有崩溃-恢复故障(crash-recovery) 的部分同步模型(partial synchronous) 通常是最有用的模型。
分布式算法如何应对这种模型?
怎么判断算法是正确的?
例如,如果我们正在为一个锁生成防护令牌,我们可能要求算法具有以下属性:
唯一性(uniqueness)
单调序列(monotonic sequence)
可用性(availability)
如果一个系统模型中的算法总是满足它在所有我们假设可能发生的情况下的性质,那么这个算法是正确的。
但是如果所有节点都挂了,可用性还有意义吗?
有必要区分两种不同的属性:安全(safety)属性和活性(liveness)属性。
两种性质的通俗理解/区别?
安全和活性的实际定义是精确的和数学的:
为什么要区分安全属性和活性属性?
证明算法正确,那么现实系统中一定正确吗?
那么,理论上抽象的系统模型是毫无价值的吗?
实际上该怎么办?
在本章中,我们讨论了分布式系统中可能发生的各种问题,包括:
这类部分失效(partial failure) 可能发生的事实是分布式系统的决定性特征。每当软件试图做任何涉及其他节点的事情时,偶尔就有可能会失败,或者随机变慢,或者根本没有响应(最终超时)。在分布式系统中,我们试图在软件中建立部分失效的容错机制,这样整个系统在即使某些组成部分被破坏的情况下,也可以继续运行。
怎么处理错误?
为了容忍错误,第一步是检测它们,但即使这样也很难。大多数系统没有检测节点是否发生故障的准确机制,所以大多数分布式算法依靠超时来确定远程节点是否仍然可用。但是,超时无法区分网络失效和节点失效,并且可变的网络延迟有时会导致节点被错误地怀疑发生故障。此外,有时一个节点可能处于降级状态:例如,由于驱动程序错误,千兆网卡可能突然下降到1 Kb/s的吞吐量。这样一个“跛行”而不是死掉的节点可能比一个干净的失效节点更难处理。
一旦检测到故障,使系统容忍它也并不容易:没有全局变量,没有共享内存,没有共同的知识,或机器之间任何其他种类的共享状态。节点甚至不能就现在是什么时间达成一致,就不用说更深奥的了。信息从一个节点流向另一个节点的唯一方法是通过不可靠的网络发送信息。重大决策不能由一个节点安全地完成,因此我们需要一个能从其他节点获得帮助的协议,并争取达到法定人数以达成一致。
但是,正如在第二部分的介绍中所讨论的那样,可伸缩性并不是使用分布式系统的唯一原因。容错和低延迟(通过将数据放置在距离用户较近的地方)是同等重要的目标,而这些不能用单个节点实现。
在本章中,我们也转换了几次话题,探讨了网络、时钟和进程的不可靠性是否是不可避免的自然规律。我们看到这并不是:有可能给网络提供硬实时的响应保证和有限的延迟,但是这样做非常昂贵,且导致硬件资源的利用率降低。大多数非安全关键系统会选择**便宜而不可靠**,而不是**昂贵和可靠**。
我们还谈到了超级计算机,它们采用可靠的组件,因此当组件发生故障时必须完全停止并重新启动。相比之下,分布式系统可以永久运行而不会在服务层面中断,因为所有的错误和维护都可以在节点级别进行处理——至少在理论上是如此。 (实际上,如果一个错误的配置变更被应用到所有的节点,仍然会使分布式系统瘫痪)。
本章一直在讲存在的问题,给我们展现了一幅黯淡的前景。
在下一章中,我们将继续讨论解决方案,并讨论一些旨在解决分布式系统中所有问题的算法。