读书笔记:Distributed Systems for Fun and Profit
分布式系统是一个宽泛的研究领域。
我们常常会听到一些关于分布式的很多技术、系统之类的名词但又不太清楚它们真正的内涵,比如说Hadoop、Spark、Paxos、Raft之类。对于分布式系统的初学者来说,更好入门的方法可能是快速了解分布式领域的一些已解决或未解决的问题、较为经典的一些方法和定理以及它们之间的关系。
在此推荐一个知乎的话题“学习分布式系统需要怎样的知识”,里面@马超Terminal的回答很好的概括了初学者需要了解的分布式系统领域的全貌。另外就是别人推荐给我的一本由六个章节组成的书,其实是大神Mikito Takada撰写的博客“Distributed Systems for Fun and Profit”。这本书揭示了分布式系统的冰山一角,它不细纠一些算法的细节,重在梳理分布式系统覆盖的东西,可读性很强。此处附上原文:
http://book.mixu.net/distsys/
下面是我自己读该博客的一些总结。
Introduction
大多数分布式编程都是在解决两个“分布式”导致的后果:
- 以光速传播的信息
- 没有成功独立的独立事件
更通俗地说,分布式编程的核心在于处理“距离”,和它所带来的一些其他的约束。这些约束决定了系统设计的可能性。希望我们在阅读完整篇文章之后,更好地了解“距离”、“时间”和一致性模型如何相互作用。
Chapter 1: Distributed systems at a high level
"分布式编程是解决您可以在使用多台计算机的单台计算机上解决的相同问题的艺术。"
第一章通过介绍一些重要的术语和概念,从高层次上介绍了分布式系统。
既然分布式系统会带来各种问题,那为什么我们还要使用分布式系统?
原因在于——“问题规模”,规模的增加使得我们已经无法使用单个节点去解决了,要么是成本太大,要么是硬件资源的瓶颈。
总的来说,我们需要分布式系统的原因在于:
- Storage:扩展存储能力
- Computation:扩展计算能力
- 目标
Scalability可扩展性:
系统(包括网络、进程任务等)能够处理越来越多工作的能力。包括一下三个维度:
- Size scalability大小(数量)可扩展性:添加更多节点应该使系统线性更快; 增长数据集不应该增加延迟。
- Geographic scalability地理(位置)可扩展性:应该可以使用多个数据中心来减少响应用户查询所需的时间,同时以一种合理的方式处理跨数据中心延迟。
- Administrative scalability管理可扩展性:添加更多节点不应增加系统的管理成本(例如管理员与机器的比率)。
Performance(and latency)性能和延迟:
系统完成的有用工作量与所用时间和资源的比。
具体可以以下面的一个或多个项来进行度量:
- Short response time/Low latency for a given piece of work:即延迟。
- High throughput(rate of processing work):吞吐量。
- Low utilization of computing resources:资源利用率。
Availabilty可用性:
系统处于运行状态的时间比例。如果用户无法访问系统,则称其不可用。
公式上可以表示为:Availability = uptime / (uptime + downtime)
技术上来说,可用性的关键在于容错。
从某种意义上说,可用性是一个比正常运行时间更广泛的概念,因为影响服务的可用性也可能是网络中断等外部因素。
Fault tolerance容错性:
一旦发生故障,系统仍然能够以明确定义的方式处理已考虑到的故障的能力。
需要明确的是,容错的“错”是系统设计时已考虑到的错误,若是没有考虑过的故障,系统显然无法兼容。
- 限制
分布式系统受两个物理因素的限制:
- 节点数(随着所需的存储和计算能力而增加)
- 节点之间的距离(信息传播,最快是以光速传播)
在这些限制将会导致
- 独立节点数量的增加会增加系统故障的可能性(降低可用性并增加管理成本)
- 独立节点数量的增加可能会增加节点之间通信的需求(随着规模的增加而降低性能)
- 地理距离的增加会增加远程节点之间通信的最小延迟(降低某些操作的性能)
- 抽象与模型
将分布式系统的设计抽象化的号出在于——消除与所要解决问题无关的现实条件,使事情更易于管理。而模型则以精确的方式描述分布式系统的关键属性。模型的分类有:
- System model (asynchronous / synchronous)
- Failure model (crash-fail, partitions, Byzantine)
- Consistency model (strong, eventual)
良好的抽象使得使用系统更容易理解。
在存在许多节点的现实状况与我们对“像单个系统一样工作”的系统的需求之间存在着紧张关系。通常,最熟悉简单的模型(例如,在分布式系统上实现共享内存抽象)太昂贵了。
此处有这样的关系:
系统内部细节 | 人对系统的理解 | 系统性能 |
---|---|---|
暴露更多 | 更难 | 更高 |
暴露更少 | 更容易 | 更低 |
CAP定理就是对分布式系统各个方面性能取舍关系的著名理论。
一个最为理想的系统必须既满足开发程序员的需求(干净舒服易理解的语义和设计)和业务需求(可用性、一致性、延迟)。
- 系统设计的常用技术——Partition and Replicate(分区和复制)
数据集在多个节点之间分配的方式非常重要。为了进行任何计算,我们需要定位数据然后对其进行操作。有两种基本技术可以应用于数据集:
- Partition分区:将数据集分割为多个节点以允许更多并行处理。
- replication复制:将数据集复制或缓存在不同的节点上,以减少客户端和服务器之间的距离,并提高容错能力。
分区提高了系统的性能(限制分区中的数据量)和可用性(对于分区数据中某个节点的失败但不会影响系统其他分区数据)。复制同样提高了系统的性能以及可用性,同时提升了系统的容错性。害怕丢失可用性或降低性能?复制数据以避免瓶颈或单点故障。计算慢?在多个系统上复制计算。慢I / O?将数据复制到本地缓存以减少延迟,或将数据复制到多台计算机上以提高吞吐量。但这里值得一提的是,复制同时也引起了一致性的问题。
有许多算法实现复制和分区,每个算法都有不同的限制和优点,需要根据您的设计目标进行评估。
Chapter 2: Up and down the level of abstraction
一个好的抽象,能平衡“可理解”和“高效”之间的关系
- 系统模型——“保留必不可少的东西,但却能广泛使用。”(System model)
分布式系统的关键属性是分布。更具体地说,分布式系统中的程序:
- 在独立节点上并发运行。
- 存在非确定性和因网络问题导致的信息丢失。
- 没有共享内存或共享时钟。
系统模型是为了抽象分布式系统环境和实现的一组假设,包括节点及它们之间通信链路的方式、关于时间和顺序的假设等。
一个强大的系统模型是做出最弱假设的模型:为这样的系统编写的任何算法都能够很好地容忍不同的环境,因为它只做很少和非常弱的假设前提。
- 系统模型中的节点(Nodes)
节点指的是参与运算和存储任务的主机。它们的任务包括执行程序、存储数据、维护一个时钟(不一定是准确的)。
节点运行确定性算法:节点执行计算任务后的本地状态以及发送的消息由接收到的消息和接收消息时的本地状态唯一确定。
节点的故障模型:
- Crash-recovery崩溃恢复故障模型:节点只能通过崩溃后停止工作,并且可能在之后恢复工作。
- Byzantine fault tolerance拜占庭容错:节点可以能以任意方式发生故障,其容错过于复杂昂贵,现实中很少处理。
- 节点的通信链接(Communication links)
通信链路将各个节点相互连接,并允许以任一方向发送消息。
讨论分布式算法的许多书籍假设每对节点之间存在单独的链接,链接为消息提供FIFO(先进先出)顺序,它们只能传递已发送的消息,并且发送的消息可以是丢失。
一般来说,最好将网络视为不可靠并受到消息丢失和延迟的影响。
当网络出现故障而节点本身仍然可操作时,会发生网络分区。发生这种情况时,消息可能会丢失或延迟,直到修复网络分区。某些客户端可以访问分区节点,因此必须与崩溃节点区别对待。
- 关于时间/顺序的假设(Time/Order)
- 同步系统模型:进程以锁步执行,消息传输延迟有一个已知的上限; 每个过程都有一个准确的时钟。
- 异步系统模型:没有时间假设。例如,流程以独立的速率执行;消息传输延迟没有限制;无时钟依赖。
解决同步系统模型中的问题更容易,因为关于执行速度,最大消息传输延迟和时钟精度的假设都有助于解决问题,因为您可以根据这些假设进行推断,并通过假设它们永远不会发生来排除不方便的故障情况。但假设同步系统模型不是特别现实,真实世界的系统最多是部分同步的:它们偶尔可以正常工作并提供一些上限,但有时会无限期地延迟消息并且时钟不同步。
- 共识问题(Consensus)
如果几个计算机(或节点)都同意某个值,那么它们就会达成共识。更正式地说:
- Agreement协议:所有正确的节点进程对某个值达成共识。
- Integrity完整性:每个正确的节点进程最多承认一个值。
- Termination终止:所有正确的节点进程最终都会同意某个值。
- Validity有效性:如果所有正确的节点进程提出相同的值V,那么所有正确的节点进程达成一致,承认值V。
共识问题是许多商业分布式系统的核心,解决共识问题可以解决几个相关的、更高级的问题,如原子广播和原子提交。
- 两个不可能理论(FLP/CAP)
FLP与设计分布式算法的人特别相关。
CAP与从业者更相关的相关结果, 需要在不同系统设计之间进行选择。
The FLP impossibility result:
不存在一个完全满足一致性的异步算法。即使该异步系统只考虑节点的failure,并且消息没有在通信中丢失,而且最多一个进程失败。
这里需要提到我们判断分布式算法是否正确的三个标准:
- Termination终止性:非失败进程最终可以做出选择。即算法必须在有限时间内结束,不能无限循环。
- Agreement一致性:所有进程必须做出相同的决议。
- Validity合法性:进程的决议值必须是其他进程提交的请求值。排除进程初始值对自身的干扰。
进一步地说,FLP不可能定理意思是不存在满足完全一致性且满足上诉三个标准的异步算法。
The CAP theorem:
该定理说明了这三个属性:
- Consistency一致性:所有节点在同一时刻拥有同一个值。
- Availability可用性:节点故障不会阻止系统(其他节点)继续运行。
- Partition tolerance:分区容错性:尽管由于网络或节点故障导致消息丢失,系统仍继续运行。
最多只可能有两个属性同时满足。
三种不同的系统类型:
- CA:包括完全严格的仲裁协议,例如2PC。
- CP:包括多数仲裁协议,例如Paxos、Raft。
- AP:包括使用冲突解决的协议,例如Dynamo、Gossip。
现实的分布式体系中,常常需要保证分区容错性,所以大多数情况下我们都需要在一致性和可用性中作抉择。
一致性模型的总结:
Strong consistency models (capable of maintaining a single copy)
- Linearizable consistency
- Sequential consistency
Weak consistency models (not strong)
- Client-centric consistency models
- Causal consistency: strongest model available
- Eventual consistency models
Chapter 3: Time and order
Order:系统完成一个任务的操作顺序。存在partial order和total order。
Time:时间,a source of order。三种不同的解释:事件顺序、时间戳、持续时间。
“各个节点时间相同?”,对此问题使用不同的时钟假设是不同的:
- Global clock全局时钟:相同(同步系统模型,但存在通信会延迟)
- Local clock本地时钟:不同(部分同步系统模型,本地有序,而全局无序)
- No clock不使用时钟:不同(异步系统模型,本地有序,远程通过交互也可以确定顺序)
Order和Time在分布式系统中至关重要。Order可以确保操作顺序,即保证了进程算法的正确性,同时也可以利用在资源争夺的先后问题中;Time除了可以用来判断Order之外,还可以判断是否有网络延迟,制作成故障检测器。
逻辑时钟:
由于物理时钟的使用存在着延迟限制,所以我们更喜欢使用逻辑时钟。
Lamport clock:
系统维护一个计数器counter
- 只要进程有效,counter + 1
- 每当进程发送消息时带上count
- 收到消息时,将计数器设置为 max(local_counter, received_counter) + 1
Vector clock:
每个节点维护一个计数器列表,每个节点一个。
故障检测器:
心跳消息+定时器
Chapter 4: Replication: preventing divergence
两种复制模型:
- Synchronous replication同步复制:接受到客户端的请求之后,各节点先同步并且返回到此节点之后,再响应客户端。
- Asynchronous replication异步复制:接受到客户端的请求之后,先响应客户端,再进行各节点先同步并且返回到此节点。
两种复制技术:
- Replication methods that prevent divergence (single copy systems)
防止分歧的复制方法(单拷贝系统) - Replication methods that risk divergence (multi-master systems)
分歧冒险的复制方法(多主系统)
第一组方法具有“行为类似于单个系统”的属性。特别是,当发生部分故障时,系统确保只有一个系统副本处于活动状态。此外,系统确保副本始终一致。这被称为共识问题。mutual exclusion, leader election, multicast, atomic broadcast都是更普遍的共识问题的实例。
Single copy consistency单拷贝一致性复制算法:
- 1n messages (asynchronous primary/backup)
- 2n messages (synchronous primary/backup)
- 4n messages (2-phase commit, Multi-Paxos)
- 6n messages (3-phase commit, Paxos with repeated leader election)
这些算法的容错性不同,根据执行期间消息交换数来进行分类。都保证了单拷贝一致性。
Primary/backup Replication
最常用的复制算法,也最基本的复制算法。也称“主/从复制”、“日志传送复制”。
所有更新操作都在主节点上进行,操作日志log通过网络传送到其他节点副本中。分为同步和异步两种类型,同步则需要两条消息(“更新”+“确认”),而异步只需要运行一条消息(“更新”)。
例子:MySQL(异步)、MongoDB(带有故障转移)
不足:只提供尽力而为的保证。在各个过程中存在各种发生故障的可能
Two phase commit (2PC)
防止上述P/B复制算法的不足,需要增加一此消息传递,因此需要两次。两个阶段:
- Voting投票:coordinator给所有participants发送请求,participants若同意则先临时更新,并返回给coordinator确认信息。
- Decision决定:coordinator决定是否真的commit,并且通知所有participants,participants永久更新。
第二个阶段允许系统在节点失败时回滚更新,保证了副本的收敛性。
2PC在性能和容错之间取得了不错的平衡。
不足:保证了CA ,但它不是分区容忍的。
Partition tolerant consensus algorithms
单拷贝一致性算法中,分区容错是我们希望做到的,而上述的算法都没有做到。
分区容忍一致性算法有:
- Paxos:在编写强一致的分区容错复制系统时,Paxos是最重要的算法之一。它在Google的许多系统中使用,包括BigTable / Megastore使用的Chubby锁管理器,Google文件系统以及Spanner。整个过程可以总结为:
Majority vote;
Dynamic master;
Robust to n/2-1 simultaneous failures as part of protocol;
Less sensitive to tail latency. - Raft:它的设计比Paxos更容易教学,同时提供相同的保证。
- ZAB:Zookeeper atomic broadcast,Zookeeper是一个为分布式系统提供协调原语的系统,并被许多以Hadoop为中心的分布式系统用于协调(例如HBase,Storm,Kafka)。
Chapter 5: Replication: accepting divergence
第四章描述的是强制执行单拷贝一致性的协议,即强一致性协议。
第五章我们允许出现多个不同的副本,但是我们需要保证它们最终趋向一致——最终一致性模型。包括
- Eventual consistency with probabilistic guarantees.概率保证的最终一致性(Dynamo)
- Eventual consistency with strong guarantees.强保证的最终一致性
Amazon Dynamo的系统设计:
- Consistent Hashing一致的散列来确定数据的关键位置
- NWR Model读写仲裁模型
- Vector Clock矢量时钟的冲突检测和读取修复
- Gossip复制算法用于保证(新)节点的复制同步
Chapter 6: Further reading and appendix
感谢了一些大神;推荐了一些分布式系统经典的书籍、论文还有系统。略。