mirror of
https://github.com/DistSysCorp/ddia.git
synced 2024-12-25 20:30:39 +08:00
Update ch08.md
remove redundant *
This commit is contained in:
parent
ade42f7223
commit
157a484ce1
16
ch08.md
16
ch08.md
@ -154,13 +154,13 @@
|
|||||||
|
|
||||||
**静态设置**。在这种环境中,如果你要为远端故障检测设置超时时间,就只能使用做实验的方式,经过足够长的时间,统计请求延迟分布。进而结合应用需求,在**检测过久**(设置长超时间隔)和**故障误报**(设置过短超时间隔)做一个权衡。
|
**静态设置**。在这种环境中,如果你要为远端故障检测设置超时时间,就只能使用做实验的方式,经过足够长的时间,统计请求延迟分布。进而结合应用需求,在**检测过久**(设置长超时间隔)和**故障误报**(设置过短超时间隔)做一个权衡。
|
||||||
|
|
||||||
**动态调整**。当然, 相比预先配置固定死超时间隔,更好的方式是,通过类似时间窗口的方式,不断监测过去一段时间内的**请求时延**和**抖动情况**,来获取请求时延的分布情况,进而动态调整超时间隔。 **Phi 累积故障检测算法**( The Φ Accrual Failure Detector**)**便是这样一种算法,Akka and Cassandra 中都用到了此种算法,它的工作原理和 TCP 重传间隔的动态调整类似。
|
**动态调整**。当然, 相比预先配置固定死超时间隔,更好的方式是,通过类似时间窗口的方式,不断监测过去一段时间内的**请求时延**和**抖动情况**,来获取请求时延的分布情况,进而动态调整超时间隔。 **Phi 累积故障检测算法**( The Φ Accrual Failure Detector)便是这样一种算法,Akka and Cassandra 中都用到了此种算法,它的工作原理和 TCP 重传间隔的动态调整类似。
|
||||||
|
|
||||||
## 同步网络和异步网络
|
## 同步网络和异步网络
|
||||||
|
|
||||||
如果我们的底层网络传输数据包时能够保证延迟上界、且不会丢包,那么基于此构建分布式系统将会容易的多。那为什么不在硬件层面解决相关问题让网络更可靠,从而让分布式软件免于关心这些复杂的细节呢?
|
如果我们的底层网络传输数据包时能够保证延迟上界、且不会丢包,那么基于此构建分布式系统将会容易的多。那为什么不在硬件层面解决相关问题让网络更可靠,从而让分布式软件免于关心这些复杂的细节呢?
|
||||||
|
|
||||||
为了回答这个问题,我们先来看一种历史产物——**固定电话网**(*fixed-line telephone network,*非 VOIP、非蜂窝网络)。在固话线路中,高延迟音频帧和意外断线都是非常罕见的。固话网会为每一次通话预留**稳定低延迟**和**充足的带宽**链路以传输语音。如果计算机网络中也采用类似的技术,生活不会很美好吗?
|
为了回答这个问题,我们先来看一种历史产物——**固定电话网**(*fixed-line telephone network* ,非 VOIP、非蜂窝网络)。在固话线路中,高延迟音频帧和意外断线都是非常罕见的。固话网会为每一次通话预留**稳定低延迟**和**充足的带宽**链路以传输语音。如果计算机网络中也采用类似的技术,生活不会很美好吗?
|
||||||
|
|
||||||
当你在固网内拨打电话时,会建立一条贯穿贯穿全链路的保证足量带宽的固定链路,我们称之为**电路**(circuit),该电路会保持到通话结束才释放。以 ISDN 网络为例,其每秒能容纳 4000 帧语音信号,当发起通话时,它会在每个方向为每帧数据分配 16 比特空间。因此,在整个通话期间,两端各自允许每 250 微秒(250us * 4000 = 1s)发送 16 比特语音数据。
|
当你在固网内拨打电话时,会建立一条贯穿贯穿全链路的保证足量带宽的固定链路,我们称之为**电路**(circuit),该电路会保持到通话结束才释放。以 ISDN 网络为例,其每秒能容纳 4000 帧语音信号,当发起通话时,它会在每个方向为每帧数据分配 16 比特空间。因此,在整个通话期间,两端各自允许每 250 微秒(250us * 4000 = 1s)发送 16 比特语音数据。
|
||||||
|
|
||||||
@ -175,7 +175,7 @@
|
|||||||
|
|
||||||
应用层给到 TCP 的任意大小的数据,都会在尽可能短的时间内被发送给对端。如果一个 TCP 连接暂时空闲,则他不会占用任何网络带宽。相比之下,在打电话时即使不说话,电路所占带宽也得一直被预留。
|
应用层给到 TCP 的任意大小的数据,都会在尽可能短的时间内被发送给对端。如果一个 TCP 连接暂时空闲,则他不会占用任何网络带宽。相比之下,在打电话时即使不说话,电路所占带宽也得一直被预留。
|
||||||
|
|
||||||
如果数据中心和互联网使用**电路交换**(*circuit-switched*)网络,他们应该能够建立一条保证稳定最大延迟的数据链路。但是事实上,由于以太网和 IP 网采用**封包交换**协议(*packet-switched protocols,*常翻译为**分组交换**,但我老感觉它不太直观),没有电路的概念,只能在数据包传送的时候对其进行排队,也不得不忍受由此带来的无界延迟。
|
如果数据中心和互联网使用**电路交换**(*circuit-switched*)网络,他们应该能够建立一条保证稳定最大延迟的数据链路。但是事实上,由于以太网和 IP 网采用**封包交换**协议(*packet-switched protocols* ,常翻译为**分组交换**,但我老感觉它不太直观),没有电路的概念,只能在数据包传送的时候对其进行排队,也不得不忍受由此带来的无界延迟。
|
||||||
|
|
||||||
那为什么数据中心网络和互联网要使用封包交换协议呢?答曰,为了应对互联网中无处不在的**突发流量**(*bursty traffic*)。在电话电路中,音频传输所需带宽是固定的;但在互联网中,各种多媒体数据(如电子邮件、网页、文件)所需带宽却是差异极大且动态变化的,我们对他们的唯一要求就是传地尽可能快。
|
那为什么数据中心网络和互联网要使用封包交换协议呢?答曰,为了应对互联网中无处不在的**突发流量**(*bursty traffic*)。在电话电路中,音频传输所需带宽是固定的;但在互联网中,各种多媒体数据(如电子邮件、网页、文件)所需带宽却是差异极大且动态变化的,我们对他们的唯一要求就是传地尽可能快。
|
||||||
|
|
||||||
@ -183,7 +183,7 @@
|
|||||||
|
|
||||||
不过,也有一些尝试来建立同时支持电路交换和封包交换的网络,如 ATM。**IB 网络**(InfiniBand)与 ATM 有一些类似之处,它在链路层实现了端到端的流量控制,从而减少了排队。具体来说,IB 使用 **QoS (**quality of service,对数据包区分优先级并进行调度)控制和**准入控制**(admission control,对发送方进行速率控制),在封包网络上模拟电路交换,或者提供概率意义上的有界时延。
|
不过,也有一些尝试来建立同时支持电路交换和封包交换的网络,如 ATM。**IB 网络**(InfiniBand)与 ATM 有一些类似之处,它在链路层实现了端到端的流量控制,从而减少了排队。具体来说,IB 使用 **QoS (**quality of service,对数据包区分优先级并进行调度)控制和**准入控制**(admission control,对发送方进行速率控制),在封包网络上模拟电路交换,或者提供概率意义上的有界时延。
|
||||||
|
|
||||||
但,现有的数据中心网络和互联网都不支持 QoS。因此,我们在设计分布式系统时,不能对网络传输的时延和稳定性有任何假设。我们必须要假定我们面对的网络会发生网络拥塞、会产生排队、会有无界延迟,在这种情况下,没有放之四海而皆准的**超时间隔。**针对不同的具体情况,需要通过经验或者实验来确定它。
|
但,现有的数据中心网络和互联网都不支持 QoS。因此,我们在设计分布式系统时,不能对网络传输的时延和稳定性有任何假设。我们必须要假定我们面对的网络会发生网络拥塞、会产生排队、会有无界延迟,在这种情况下,没有放之四海而皆准的**超时间隔** 。针对不同的具体情况,需要通过经验或者实验来确定它。
|
||||||
|
|
||||||
> **通信时延和资源利用**
|
> **通信时延和资源利用**
|
||||||
>
|
>
|
||||||
@ -211,7 +211,7 @@
|
|||||||
7. 该缓存条目何时超时?
|
7. 该缓存条目何时超时?
|
||||||
8. 日志中这条错误消息的时间戳是什么?
|
8. 日志中这条错误消息的时间戳是什么?
|
||||||
|
|
||||||
例子 1~4 测量的是**时间间隔**(durations),例子 5~8 描述的是**时间点**(points in time)。在分布式系统中,时间是一个棘手的问题。因为两个机器间的通信不是瞬时完成的,虽然我们知道一条消息的接收时间一定小于发送时间,但由于**通信延迟的不确定性**,我们无法知道具体晚了多久。因此,发生在分布式系统内多个机器的事件,很难准确地确定其先后顺序。
|
例子 1-4 测量的是**时间间隔**(durations),例子 5-8 描述的是**时间点**(points in time)。在分布式系统中,时间是一个棘手的问题。因为两个机器间的通信不是瞬时完成的,虽然我们知道一条消息的接收时间一定小于发送时间,但由于**通信延迟的不确定性**,我们无法知道具体晚了多久。因此,发生在分布式系统内多个机器的事件,很难准确地确定其先后顺序。
|
||||||
|
|
||||||
更进一步,网络中的每个机器都有自己的系统时钟,通常是用**石英振荡器**做成的特殊硬件计时的,并且通常是独立供电的,即使系统宕机、断电也能持续运转。但这种时钟通常不是非常准确,即有的机器可能走的稍微快一些,有的可能就慢一些。因此,实践中,常通过 **NTP**(网络时间协议)对机器进行自动校准。其大致原理是,首先使用更精确时钟(如 GPS 接收器)构建一组**可信服务器**作为时钟源(比如阿里云的源),然后再利用这组服务器通过网络校准其他机器。
|
更进一步,网络中的每个机器都有自己的系统时钟,通常是用**石英振荡器**做成的特殊硬件计时的,并且通常是独立供电的,即使系统宕机、断电也能持续运转。但这种时钟通常不是非常准确,即有的机器可能走的稍微快一些,有的可能就慢一些。因此,实践中,常通过 **NTP**(网络时间协议)对机器进行自动校准。其大致原理是,首先使用更精确时钟(如 GPS 接收器)构建一组**可信服务器**作为时钟源(比如阿里云的源),然后再利用这组服务器通过网络校准其他机器。
|
||||||
|
|
||||||
@ -311,7 +311,7 @@
|
|||||||
|
|
||||||
但不幸,大多数服务器的时钟系统 API 在给出时间点时,并不会一并给出对应的不确定区间。例如,你使用 `clock_gettime()` 系统调用获取时间戳时,返回值并不包括其置信区间,因此你无法知道这个时间点的误差是 5 毫秒还是 5 年。
|
但不幸,大多数服务器的时钟系统 API 在给出时间点时,并不会一并给出对应的不确定区间。例如,你使用 `clock_gettime()` 系统调用获取时间戳时,返回值并不包括其置信区间,因此你无法知道这个时间点的误差是 5 毫秒还是 5 年。
|
||||||
|
|
||||||
一个有趣的反例是谷歌在 Spanner 系统中使用的 *TrueTime* API,会显式的给出置信区间。当你向 TrueTime 系统询问当前时钟时,会得到两个值,或者说一个区间:`[*earliest*, *latest*]`,前者是最早可能的时间戳。后者是最迟可能的时间错。通过该不确定预估,我们可以确定准确时间点就在该时钟范围内。此时,区间的大小取决于,上一次同步过后本地石英钟的漂移多少。
|
一个有趣的反例是谷歌在 Spanner 系统中使用的 *TrueTime* API,会显式的给出置信区间。当你向 TrueTime 系统询问当前时钟时,会得到两个值,或者说一个区间:`[earliest, latest]`,前者是最早可能的时间戳。后者是最迟可能的时间错。通过该不确定预估,我们可以确定准确时间点就在该时钟范围内。此时,区间的大小取决于,上一次同步过后本地石英钟的漂移多少。
|
||||||
|
|
||||||
### 用于快照的时钟同步
|
### 用于快照的时钟同步
|
||||||
|
|
||||||
@ -391,7 +391,7 @@ while (true) {
|
|||||||
|
|
||||||
我们需要在全软件栈进行优化才能提供实时保证:
|
我们需要在全软件栈进行优化才能提供实时保证:
|
||||||
|
|
||||||
1. **在操作系统上**,需要能提供指定所需 CPU 时间片的实时操作系统(*real-time operating system,*RTOS)。
|
1. **在操作系统上**,需要能提供指定所需 CPU 时间片的实时操作系统(*real-time operating system* ,RTOS)。
|
||||||
2. **在依赖库中**,所有的函数都需要注释其运行时间的上界。
|
2. **在依赖库中**,所有的函数都需要注释其运行时间的上界。
|
||||||
3. **在内存分配上**,要限制甚至禁止动态内存分配(会有实时 GC 器,但不会占用太多时间)。
|
3. **在内存分配上**,要限制甚至禁止动态内存分配(会有实时 GC 器,但不会占用太多时间)。
|
||||||
4. **在观测和测试上**,需要进行详尽的衡量和测试,以保证满足实时要求。
|
4. **在观测和测试上**,需要进行详尽的衡量和测试,以保证满足实时要求。
|
||||||
@ -578,4 +578,4 @@ Quorum 算法多要求每个节点记住其所声明的内容。如果由于某
|
|||||||
|
|
||||||
但这并不是说,理论的、抽象的系统模型毫无价值。事实上,恰恰相反,他能帮助我们将复杂真实的系统,**提炼**为可处理、可推演的**有限故障集**。据此,我们可以剖析问题,并进行系统性的解决问题。在特定的系统模型下,只要算法满足特定性质,我们就可以**证明算法的正确性。**
|
但这并不是说,理论的、抽象的系统模型毫无价值。事实上,恰恰相反,他能帮助我们将复杂真实的系统,**提炼**为可处理、可推演的**有限故障集**。据此,我们可以剖析问题,并进行系统性的解决问题。在特定的系统模型下,只要算法满足特定性质,我们就可以**证明算法的正确性。**
|
||||||
|
|
||||||
即使算法被证明是正确的,但在实际环境中,其实现并不一定总能够正确运行。不过,这已经是一个很好地开端了,系统的分析能够很快的暴露算法的问题。而在真实系统中,这些问题只有经过很长时间、当你的假设被某些极端情况打破后才可能发现。**理论分析**(Theoretical analysis)和**实践测试**(empirical testing)需要并重。
|
即使算法被证明是正确的,但在实际环境中,其实现并不一定总能够正确运行。不过,这已经是一个很好地开端了,系统的分析能够很快的暴露算法的问题。而在真实系统中,这些问题只有经过很长时间、当你的假设被某些极端情况打破后才可能发现。**理论分析**(Theoretical analysis)和**实践测试**(empirical testing)需要并重。
|
||||||
|
Loading…
Reference in New Issue
Block a user