写点什么

DDIA 读书笔记(7)分布式系统的问题

用户头像
莫黎
关注
发布于: 2020 年 12 月 21 日

根据墨菲定律,我们需要用最悲观的态度来看待分布式系统中可能出现的问题,本文将对这些问题进行总结。


故障与部分失效

基于单台计算机构建的系统是非常可靠的,因为单台计算机本身就十分可靠,所有的错误都是确定的,存在任何问题都会导致系统崩溃。即要么功能完好,要么完全失效,不会有介于两者之间的结果。


可一但系统构建于多台计算机之上,不可靠的东西就多了起来。最关键的是系统会存在部分失效的可能,而且失效的部分是不确定的,不可预测的,你可能连那部分是否失效了都不知道。


因此分布式系统必须接受部分失效的可能性,并在软件层面做好容错机制。

不可靠的网络

计算机之间的通信只能依靠网络,互联网和数据中心大部分是异步分组网络(asynchronous packet networks)。这种网络不能保证数据包什么时候到达,是否到达。请求发出没有得到响应可能会有很多种的情况,诸如请求丢失、远程节点失效,远程节点处理了请求但是响应丢失了等。


要命的是,发送者甚至没办法辨别数据包是否发出去了,处理这种问题通用方法是 超时(Timeout),在发送一段时间后就放弃等待,而不管发送情况如何。


网络的不确定性导致判断一个节点是否正常工作也是一件较为困难的事情。虽然可以通过各种层面的试探来判断目标情况,比如查看目前进程是否在监听目标端口,目标机器的硬件是否有异常等,收到异常反馈能够证明目标失效了,但是没有收到异常反馈不能证明目标没有失效。确保请求成功的唯一手段是获得目标应用程序的积极响应,如果在任意一个环节出了问题,都要假设没有收到回应,并通过重试或超时的手段来判定失效。


超时的阀值设定需要大量的考究,等待时间越长系统的可靠性就越低。等待时间太短也会有问题,过早地判定节点死亡会带来一些额外的风险:节点可能仍在正常工作或是短暂的无响应,贸然被其他节点接管会导致任务重复执行,并加重其他节点的负担,尤其是在高负载的情况,很可能会导致级联失效。


不可靠的时钟

依赖时钟的功能有两种,一种是测量持续时间(比如发送请求与接收响应的时间间隔)、一种是描述时间点(特定的时间发生的事件)。在分布式系统中,每个机器都有自己的时钟,每个时钟都会有一定的误差,再加上网络中可变的延迟,很难确定涉及到多台机器的事件的发生顺序.


单调钟与时钟

现代计算机都会内置两种不同的时钟来应对不同的功能:单调钟和时钟。


时钟是与 NTP 同步的,在理想情况下两台机器的时间戳是一致的,但时钟也有坑的地方,如果本地时钟与 NTP 服务器差的太远,可能会被强制重置,在本地应用程序的视角下就是时间跳跃了。因此时钟不能用来测量持续时间


单调钟保证了它的时间总是前进的,因此可用来测量持续时间,如果 NTP 协议检测到本地石英钟有偏差,会调整本地时钟的频率以维持尽量同步。


依赖时钟会发生的问题

最常见的就是跨节点的事件排序,不同节点的时钟不会完全同步,当两个节点同时接收到了一个写入请求,依赖时钟判断写入的先后顺序是有风险的,甚至会导致其中一个写入请求的丢失。


另一个例子是由进程暂停的特性引起的问题,假设数据库只有一个主节点可以接受写入,且节点之间依赖租约来维持身份。而租约的实现需要依赖于同步时钟。假设住主节点的进程因为一些原因突然被暂停了很长一段时间(可以有十几秒),其他节点因为租约到期的原因诞生了新的主节点,而旧的主节点进程恢复后不会马上检查租约(进程的停顿在进程内部的代码无法察觉,只会继续执行下去),此时就会出现两个主节点。


知识、真相与谎言

在分布式系统中,我们需要对系统模型作出若干假设,并基于这些假设来构建一个可靠的系统。


分布式系统的核心问题在于,网络中的节点如同大海中的孤岛,它没有任何手段可以确定信息,只能依靠有限的手段来猜测和推理。比如节点通过与其他节点进行信息交换来确定对方节点的状态(基于节点之间不会互相欺骗的前提来确保信息的真实性)。如果对方节点无响应,就没有办法区分是网络问题还是节点问题。


节点连自身的状态都无法判断,因为会遇到进程暂停、垃圾回收、网络故障等一系列问题,发生故障期间节点自身是无法察觉的。因此分布式系统绝不能依赖单个节点,任何决策都需要由多个节点投票,最常见的法定票数就是取节点数量的一半以上。


发布于: 2020 年 12 月 21 日阅读数: 45
用户头像

莫黎

关注

还未添加个人签名 2017.11.06 加入

还未添加个人简介

评论

发布
暂无评论
DDIA 读书笔记(7)分布式系统的问题