翻译:Distributed systems for fun and profit(基础)
计算机系统有两个基本任务:
- 存储
- 计算
分布式编程是一门艺术, 它是通过多个计算机系统来处理单个计算机系统不适合处理的问题。
如果给你无线的资源和R&D 时间, 分布式系统并不是必须的,所有的存储和计算资源都可以做在一个魔法的盒子当中,用来处理遇到的问题。
然而很多人没有无限的资源。这是一个投资和收益的问题,如果一个问题很小,你可以通过升级单个计算机硬件的性能来处理,但是随着系统的不大扩大,单纯的升级计算机硬件将无法解决问题或者升级硬件不在划算时, 这时候分布式系统就有了它发挥作用的地方。
现在最好的方式是通过设计容错系统并使用中档商业的硬件已经可维护的方式来处理大系统问题。
理想状况下,添加服务器可以让系统性能线性增加。当然这种情况是不可能的,分布的系统会有一些额外的开:数据需要下计算机之间相互拷贝,以及计算机任务之间的相互合作等等。这就是为什么我们需要学习分布式系统算法:这些算法提供特定问题的高效解决方案,什么是可以实现的,什么是不可以实现的,怎么以最小的消耗正确的实现功能。
本文集中分析普通商业数据中心采用的分布式设计。比如:我们在对待特定的问题时,有可能采用独特的网络配置或者不同的共享内存的设定。另外,本文主要关注系统设计而不是优化特定的设计。
我们的目标:扩展性和其他好的效果
scalability
在我看来,所有这些事情都开始于处理大问题。
小问题很容易解决,但当问题变大后,解决问题会变的困难。你可以很容易的举起一个巧克力,但是很难举起以座山。很容计算一个房间有多少人,计算一个城市有多少人会很困难。所以所有事情都跟扩展相关,通常来讲一个具有扩展性的系统不会因为规模的变大而变的越来越糟糕。这里有关于扩展性的定义:
scalability:一种能力能够很容易的适应所要解决问题的变大。
系统的扩展性体现在下面3个方面:
- 大小的扩展性:添加node 可以让系统性能线性增加,数据库的增大不会增加延迟。
- 地理上的扩展性:当以明智的方式处理跨数据中心的延迟时,有办法能够通过多数据中心的方式来降低延迟
- 管理的扩展性:增加node不会增加管理的负担
一个扩展性系统会持续的遇到用户数量增加的问题,这里有两个相关的概念:
Performance(and latency)
Performance(and latency):完成有效工作使用的时间和资源的大小
根据上下文,这一特性有下面3个方面:
- 低延迟
- 高吞吐
- 更少的资源消耗
要实现这些目标有时候需要做一些权衡,有时候为了实现高吞吐会对数据进行一些打包和解包,这样就会导致延迟的增加。
低延迟是系统性能方面很有趣的一个概念,因为它跟物理限制非常相关,很难分析。
Availablity(and fault tolerance)
一个分布式系统相关的第二个概念是可用性
Availability:系统处于有效工作状态的比例
分布式系统允许我们实现单机系统无法实现的功能,比如,单机系统无法容忍任何错误,失败或者成功。
分布式系统使用一些不可靠的组件,并在这些组件之上建立一个可靠的系统。
没有冗余设计的系统的可用性以来于它使用的底层组件,有冗余设计的系统可以容忍局部失败而变的更加可用。冗余设计依赖于你怎么看待它:组件、服务、数据中心等等。
总结起来:可用性=uptime/(uptime + downtime)
可用性从技术角度来讲更多的是关于容错性,这里有一些例子:
Availability % | How much downtime is allowed per year? |
90% ("one nine") | More than a month |
99% ("two nines") | Less than 4 days |
99.9% ("three nines") | Less than 9 hours |
99.99% ("four nines") | Less than an hour |
99.999% ("five nines") | ~ 5 minutes |
99.9999% ("six nines") | ~ 31 seconds |
我们最好的方式实现更高的容错性来保证系统的可用性。那么容错性指什么呢?
fault tolerance:当系统出错时,能够很好的运行的能力。
考虑系统可能发生的错误,通过设计能保证在这些错误发生时,系统能够很好的运行。你没办法容错那些你没发预料的错误。
什么阻碍了达成这么目标
分布式系统受限于下面两个物理因素:
- 系统由很多节点组成(随着存储和计算需求的增长而增长)
- 节点之间的距离(信息传输最大的速度为光速)
处理这两个约束会遇到下面的问题:
- 相互独立节点的增多会导致系统发生错误的时间增加(可用性降低以及管理成本的则增加)
- 节点的增加导致通信的增加(性能会随着节点规模的增加而降低)
- 节点之间物理距离的增加导致延迟的增加(对于某些操作性能会降低)
性能和可用性都是由系统的外在表现定义的。简单讲就是系统提供服务的能力:系统保证数据能够多快速的写入?写入之后,是否能够保证数据的耐久性?计算任务如果快速的执行并返回结果?如果系统组件发生错误,将对系统有哪些影响?
还有一个被隐形提交的规范:可理解性。 错误和异常是不同的:错误是不正确的行为,而异常是没有预想到的行为。
抽象和模型
抽象就是将复杂物体的一个或几个特性抽出去,而只注意其他特性的。模型是用精确的方式来描述系统的关系特性。我将在下一章节详细介绍一些模型:
- 系统模型(同步/异步)
- 错误处理模型(crash-fail, 分区, 拜占庭)
- 数据一致性模型(强一致,最终一致)
好的抽象让系统容易被理解,并且通常会根据特定的用途关注特定的几个点。
现实当中系统有很多节点,这与我们的目标“让系统像一个节点一样工作”有很大的落差。通常,最熟悉的模型(如为分布式系统实现一个共享内存抽象)是很昂贵的。
一个系统如果提供弱保证通常会对操作更加自由以及性能会根据高。通常会通过暴露更多系统内部的系统来获得系统的性能。隐藏细节可以让系统更加容易被理解,而暴露内部细节通常可以获得更好的性能(因为这样跟接近真实的系统)。
很多错误让实现一个分布式系统像单个系统一样变的困难。网路延迟和网路分区意味着我们需要在可用性和一致性之间做出困能的决定。
下一章介绍的CAP理论会涉及这些问题。一个理想的系统需要满足编程需求(简单的语法)和商业需求(可用性/一致性/低延迟)
设计技术:分区和复制
让数据在分布在多个节点上面是非常重要的。为了计算,我们需要定位这些数据并且对它们进行操作。
这里有两个基本的概念用于数据。把数据分拆后分布到不同的节点(分区) 以允许系统并行允许。还可以把数据拷贝或者缓存到不同的节点以降低客户端和服务端的距离,并且实现更好的容错(复制)。
分而治之-分区和复制
下面的图片将表明这两种方式的不同:分区数据(A和B)被分拆成成不同的数据片, 而复制数据(C)被拷贝到不同的位置。
这是解决分布式系统问题的组合拳。当然,技巧是挑选合适的技术。由很多算法来实现分区和复制,每一种都有不同的优缺点。
分区
分区是指把数据集分拆成相互独立的更小的数据集,用于降低大数据集增长的影响。
- 分区提高系统性能(限制系统检测数据集的大小,把相关联的数据分拆到同一个分区)
- 分区提高可用性(容忍分区失败,提高判断系统失败时失败节点的数量)
复制
复制是指拷贝数据到多个节点上。这将允许更多个服务进行计算。
来复制吧。生命中所有问题的起因和解决方法。
复制-解决延迟问题主要的方法。
- 复制提高性能(通过为新增的数据拷贝增强计算能力和带宽)
- 复制提高可用性(通过添加拷贝数据,提高判断系统失败时失败节点的数量)
复制需要提供额外带宽和缓存并且需要通过某种方式来维护数据一致性。
复制技术允许我们实现扩展性、性能和容错。害怕失去可用性和性能降低?复制数据可以避免性能瓶颈和单点故障。低效计算?在多个系统上复制计算。I/O 慢? 复制数据到本地缓存来降低延迟或者复制到多个节点提高吞吐量。
复制同时也带来了很多问题,需要同步各个独立节点上面的数据-数据复制需要一个一致性模型。
一致性模型的选择是很重要的:一个好的一致性模型可以使编程简单,并且能够让商业目标比如高可用或者强一致性。
只有强一致模型允许我们编程中感觉不到数据复制,其它的一致性模型暴露一些内部的复制机制给外部编程。然后弱一致性可以降低延迟和提高可用性-理解起来并不困难只是有点不同。
深度阅读
- The Datacenter as a Computer - An Introduction to the Design of Warehouse-Scale Machines - Barroso & Hölzle, 2008
- Fallacies of Distributed Computing
- Notes on Distributed Systems for Young Bloods - Hodges, 2013