云计算及分布式系统

期末论文:

分布式系统的核心问题:
1,一致性问题
在分布式系统中,一致性(Consistency,早期也叫 Agreement)是指对于系统中的多个服务节点,给定一系列操作,在协议(往往通过某种共识算法)保障下,试图使得它们对处理结果达成某种程度的一致。

如果分布式系统能实现“一致”,对外就可以呈现为一个功能正常的,且性能和稳定性都要好很多的“虚处理节点”。

举个例子,某影视公司旗下有西单和中关村的两个电影院,都出售某电影票,票一共就一万张。那么,顾客到达某个电影院买票的时候,售票员该怎么决策是否该卖这张票,才能避免超售呢?当电影院个数更多的时候呢?

这个问题在人类世界中,看起来似乎没那么难,你看,英国人不是刚靠 投票 达成了“某种一致”吗?

注意:一致性并不代表结果正确与否,而是系统对外呈现的状态一致与否,例如,所有节点都达成失败状态也是一种一致。

挑战

在实际的计算机集群系统(看似强大的计算机系统,很多地方都比人类世界要脆弱的多)中,存在如下的问题:

  • 节点之间的网络通讯是不可靠的,包括任意延迟和内容故障;
  • 节点的处理可能是错误的,甚至节点自身随时可能宕机;
  • 同步调用会让系统变得不具备可扩展性。

要解决这些挑战,愿意动脑筋的读者可能会很快想出一些不错的思路。

为了简化理解,仍然以两个电影院一起卖票的例子。可能有如下的解决思路:

  • 每次要卖一张票前打电话给另外一家电影院,确认下当前票数并没超售;
  • 两家电影院提前约好,奇数小时内一家可以卖票,偶数小时内另外一家可以卖;
  • 成立一个第三方的存票机构,票都放到他那里,每次卖票找他询问;
  • 更多……

这些思路大致都是可行的。实际上,这些方法背后的思想,将可能引发不一致的并行操作进行串行化,就是现在计算机系统里处理分布式一致性问题的基础思路和唯一秘诀。只是因为计算机系统比较傻,需要考虑得更全面一些;而人们又希望计算机系统能工作的更快更稳定,所以算法需要设计得再精巧一些。

要求

规范的说,理想的分布式系统一致性应该满足:

  • 可终止性(Termination):一致的结果在有限时间内能完成;
  • 共识性(Consensus):不同节点最终完成决策的结果应该相同;
  • 合法性(Validity):决策的结果必须是其它进程提出的提案。

第一点很容易理解,这是计算机系统可以被使用的前提。需要注意,在现实生活中这点并不是总能得到保障的,例如取款机有时候会是“服务中断”状态,电话有时候是“无法连通”的。

第二点看似容易,但是隐藏了一些潜在信息。算法考虑的是任意的情形,凡事一旦推广到任意情形,就往往有一些惊人的结果。例如现在就剩一张票了,中关村和西单的电影院也分别刚确认过这张票的存在,然后两个电影院同时来了一个顾客要买票,从各自“观察”看来,自己的顾客都是第一个到的……怎么能达成结果的共识呢?记住我们的唯一秘诀:核心在于需要把两件事情进行排序,而且这个顺序还得是大家都认可的

第三点看似绕口,但是其实比较容易理解,即达成的结果必须是节点执行操作的结果。仍以卖票为例,如果两个影院各自卖出去一千张,那么达成的结果就是还剩八千张,决不能认为票售光了。

带约束的一致性

做过分布式系统的读者应该能意识到,绝对理想的强一致性(Strong Consistency)代价很大。除非不发生任何故障,所有节点之间的通信无需任何时间,这个时候其实就等价于一台机器了。实际上,越强的一致性要求往往意味着越弱的性能。

一般的,强一致性(Strong Consistency)主要包括下面两类:

  • 顺序一致性(Sequential Consistency):Leslie Lamport 1979 年经典论文《How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中提出,是一种比较强的约束,保证所有进程看到的 全局执行顺序(total order)一致,并且每个进程看自身的执行(local order)跟实际发生顺序一致。例如,某进程先执行 A,后执行 B,则实际得到的全局结果中就应该为 A 在 B 前面,而不能反过来。同时所有其它进程在全局上也应该看到这个顺序。顺序一致性实际上限制了各进程内指令的偏序关系,但不在进程间按照物理时间进行全局排序。
  • 线性一致性(Linearizability Consistency):Maurice P. Herlihy 与 Jeannette M. Wing 在 1990 年经典论文《Linearizability: A Correctness Condition for Concurrent Objects》中共同提出,在顺序一致性前提下加强了进程间的操作排序,形成唯一的全局顺序(系统等价于是顺序执行,所有进程看到的所有操作的序列顺序都一致,并且跟实际发生顺序一致),是很强的原子性保证。但是比较难实现,目前基本上要么依赖于全局的时钟或锁,要么通过一些复杂算法实现,性能往往不高。

目前,高精度的石英钟的漂移率为 [图片上传失败...(image-10f65b-1515137914689)]

,人类目前最准确的原子震荡时钟的漂移率为 [图片上传失败...(image-ef2d83-1515137914689)]

。Google 曾在其分布式数据库 Spanner 中采用基于原子时钟和 GPS 的“TrueTime”方案,能够将不同数据中心的时间偏差控制在 10ms 以内。方案简单粗暴而有效,但存在成本较高的问题。

强一致的系统往往比较难实现。很多时候,人们发现实际需求并没有那么强,可以适当放宽一致性要求,降低系统实现的难度。例如在一定约束下实现所谓最终一致性(Eventual Consistency),即总会存在一个时刻(而不是立刻),系统达到一致的状态,这对于大部分的 Web 系统来说已经足够了。这一类弱化的一致性,被笼统称为弱一致性(Weak Consistency)。

莫非分布式领域也有一个测不准原理?这个世界为何会有这么多的约束呢?

共识算法

实际上,要保障系统满足不同程度的一致性,往往需要通过共识算法来达成。

共识算法解决的是对某个提案(Proposal),大家达成一致意见的过程。提案的含义在分布式系统中十分宽泛,如多个事件发生的顺序、某个键对应的值、谁是领导……等等,可以认为任何需要达成一致的信息都是一个提案。

注:实践中,一致性的结果往往还需要客户端的特殊支持,典型地通过访问足够多个服务节点来验证确保获取共识后结果。

问题挑战
实际上,如果分布式系统中各个节点都能保证以十分强大的性能(瞬间响应、高吞吐)无故障的运行,则实现共识过程并不复杂,简单通过多播过程投票即可。

很可惜的是,现实中这样“完美”的系统并不存在,如响应请求往往存在时延、网络会发生中断、节点会发生故障、甚至存在恶意节点故意要破坏系统。

一般地,把故障(不响应)的情况称为“非拜占庭错误”,恶意响应的情况称为“拜占庭错误”(对应节点为拜占庭节点)。

常见算法
针对非拜占庭错误的情况,一般包括 Paxos、Raft 及其变种。

对于要能容忍拜占庭错误的情况,一般包括 PBFT 系列、PoW 系列算法等。从概率角度,PBFT 系列算法是确定的,一旦达成共识就不可逆转;而 PoW 系列算法则是不确定的,随着时间推移,被推翻的概率越来越小。

理论界限
搞学术的人都喜欢对问题先确定一个界限,那么,这个问题的最坏界限在哪里呢?很不幸,一般情况下,分布式系统的共识问题无解。

FLP 不可能性原理

当节点之间的通信网络自身不可靠情况下,很显然,无法确保实现共识。但好在,一个设计得当的网络可以在大概率上实现可靠的通信。

然而,即便在网络通信可靠情况下,一个可扩展的分布式系统的共识问题的下限是无解。

这个结论,被称为 FLP 不可能性 原理,可以看做分布式领域的“测不准原理”。

FLP 不可能原理:在网络可靠,存在节点失效(即便只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性算法。

提出该定理的论文是由 Fischer, Lynch 和 Patterson 三位作者于 1985 年发表,该论文后来获得了 Dijkstra(就是发明最短路径算法的那位)奖。

FLP 不可能原理实际上告诉人们,不要浪费时间去为异步分布式系统设计在任意场景下都能实现共识的算法。

理解这一原理的一个不严谨的例子是:

三个人在不同房间,进行投票(投票结果是 0 或者 1)。三个人彼此可以通过电话进行沟通,但经常会有人时不时地睡着。比如某个时候,A 投票 0,B 投票 1,C 收到了两人的投票,然后 C 睡着了。A 和 B 则永远无法在有限时间内获知最终的结果。如果可以重新投票,则类似情形每次在取得结果前发生:(

FLP 原理实际上说明对于允许节点失效情况下,纯粹异步系统无法确保一致性在有限时间内完成。

这岂不是意味着研究一致性问题压根没有意义吗?

先别这么悲观,学术界做研究,考虑的是数学和物理意义上最极端的情形,很多时候现实生活要美好的多(感谢这个世界如此鲁棒!)。例如,上面例子中描述的最坏情形,总会发生的概率并没有那么大。工程实现上多试几次,很大可能就成功了。

科学告诉你什么是不可能的;工程则告诉你,付出一些代价,我可以把它变成可能。

这就是工程的魅力。

那么,退一步讲,在付出一些代价的情况下,我们能做到多少?

回答这一问题的是另一个很出名的原理:CAP 原理。

科学上告诉你去赌场赌博从概率上总会是输钱的;工程则告诉你,如果你愿意接受最终输钱的结果,中间说不定偶尔能小赢几笔呢!?

CAP 原理

CAP 原理最早由 Eric Brewer 在 2000 年,ACM 组织的一个研讨会上提出猜想,后来 Lynch 等人进行了证明。

该原理被认为是分布式系统领域的重要原理。

定义
分布式计算系统不可能同时确保一致性(Consistency)、可用性(Availablity)和分区容忍性(Partition),设计中往往需要弱化对某个特性的保证。

一致性(Consistency):任何操作应该都是原子的,发生在后面的事件能看到前面事件发生导致的结果,注意这里指的是强一致性;
可用性(Availablity):在有限时间内,任何非失败节点都能应答请求;
分区容忍性(Partition):网络可能发生分区,即节点之间的通信不可保障。
比较直观地理解,当网络可能出现分区时候,系统是无法同时保证一致性和可用性的。要么,节点收到请求后因为没有得到其他人的确认就不应答,要么节点只能应答非一致的结果。

好在大部分时候网络被认为是可靠的,因此系统可以提供一致可靠的服务;当网络不可靠时,系统要么牺牲掉一致性(大部分时候都是如此),要么牺牲掉可用性。

应用场景
既然 CAP 不可同时满足,则设计系统时候必然要弱化对某个特性的支持。

弱化一致性
对结果一致性不敏感的应用,可以允许在新版本上线后过一段时间才更新成功,期间不保证一致性。

例如网站静态页面内容、实时性较弱的查询类数据库等,CouchDB、Cassandra 等为此设计。

弱化可用性
对结果一致性很敏感的应用,例如银行取款机,当系统故障时候会拒绝服务。MongoDB、Redis 等为此设计。

Paxos、Raft 等算法,主要处理这种情况。

弱化分区容忍性
现实中,网络分区出现概率减小,但较难避免。某些关系型数据库、ZooKeeper 即为此设计。

实践中,网络通过双通道等机制增强可靠性,达到高稳定的网络通信。

你可能感兴趣的:(云计算及分布式系统)