分布式系统与核心算法

本文深入探讨了分布式系统中的一致性问题、共识算法、CAP原理等关键概念,解析了Paxos、Raft等算法的工作机制,以及拜占庭问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:轻易科技知行研发部 - 王彧

最近了解了下分布式系统原理和算法,做下整理。

 一、致性问题

一致性问题是分布式领域最为基础也是最为重要的问题。如果分布式系统能实现“一致”,对外就可以呈现为一个完美的、可扩展的“虚拟节点”,相对物理节点具有的优越性能和稳定性。这也是分布式系统希望能实现的最终目标。

       1、定义与重要性

        一致性(consistency),早期叫agreement,是指对于分布式系统中的多个服务节点,给定一系列操作,在约定协议的保障下,试图使得它们对处理结果达成“某种程度”的认同。

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

      2、问题与挑战

         1)节点之间的网络通信是不可靠的,包括消息延迟、乱序和内容错误等;

         2)节点的处理时间无法保障,结果可能出现错误,甚至节点自身可能发生启机;

         3)同步调用可以简化设计,但会严重降低分布式系统的可扩展性,甚至使其退化为单点系统;

             传统分布式系统的设计思路,都是将可能引发不一致的并行操作进行串行化;

       3、一致性要求

         1)可终止性(termination):一致的结果在有限时间内能完成;

         2)约同性(agreement):不同节点最终完成决策的结果是相同的;

         3)合法性(validity):决策的结果必须是某个节点提出的提案。

         区块链的设计思路:把多件事情进行排序,而且这个顺序还得是大家认可的。

       4、带约束的一致性

         传统分布式系统要实现理想的严格一致性(strict consistency)代价很大。除非系统不发生任何故障,而且节点之间的通信无需任何时间,这个时候整个系统就等同于一台机器了。实际上越强的一致性要求往往会造成越弱的处理性能,以及越差的可扩展性。

         1)强一致性(strong consistency)主要包括2类:

              a.顺序一致性(sequential consistency):是一种比较强的约束,保证所有进程看到的全局执行顺序(total order)一致,并且每个进程看自身的执行顺序(local order)跟实际发生顺序一致。顺序一致性实际上限制了各进程内指令的偏序关系,但不在进程间按照物理时间进行全局排序;

              b.线性一致性(linearizability consistency):在顺序一致性的前提下加强了进程间的操作顺序,形成唯一的全局顺序(系统等价于是顺序执行,所有进程看到的所有操作的序列顺序都一致,并且跟实际发生顺序一致),是很强的院子性保证。但比较难实现,目前基本上依赖于全局的时钟或锁,要么通过一些复杂的算法实现,性能往往不高。

         2)弱一致性(weak consistency)

             由于强一致性的系统往往比较难实现,而且很多时候,实际需求并没有那么严格需要的强一致性。因此,可以适当的放宽对一致性的要求,从而简单系统实现的难度。例如在一定约束下实现所谓最终一致性(eventual consistency),即总会存在一个时刻(而不是立刻),让系统达到一致状态。大部分web系统实现的都是最终一致性,相对强一致性,这一类在某些方面弱化的一致性都统称弱一致性。

二.共识算法

        一致性往往指分布系统中多个副本对外呈现的数据的状态。如前面提到的顺序一致性、线性一致性,描述了多个节点对数据状态的维护能力。而共识则描述了分布式系统中多个节点间,彼此对某个状态达成一致结果的过程。

        因此,一致性描述的是结果状态,共识则是一种手段。达成某种共识并不意味着就保障了一致性。实践中,要保障系统满足不同程度的一致性,核心过程往往需要通过共识算法来达成。

        共识算法解决的是对某个提案(proposal)大家达成一致意见的过程。

        提案的含义在分布式系统中十分宽泛,如多个事件发生的顺序、某个键对应的值、谁是领导......等等。可以认为任何可以达成一致的信息都是一个提案。

        对于分布式系统来讲,各个节点通常都是相同的确定性状态机模型(又称状态机复制问题,state-machine replication),从相同初始状态开始接收相同顺序的指令,则可以保证相同的结果状态。

因此,系统中多个节点最关键的是对多个事件的顺序进行共识,即排序。

        1、问题与挑战

         一般把出现故障(crash 或 fail-stop,即不响应)但不会伪造信息的情况成为“非拜占庭错误”(non-byzantine fault) 或“故障错误”(Crash Fault);伪造信息恶意响应的情况称为“拜占庭错误”(Byzantine Fault),对应节点为拜占庭节点。

        2、常见算法

        根据解决的是非拜占庭错误情况还是拜占庭错误情况,共识算法可以分为Crash Fault Tolerance (CFT)类算法和Byzantine Fault Tolerance(BFT) 算法。

        针对常见的非拜占庭错误的情况,已经存在一些经典的解决算法,包括Paxos、Raft及其变种等。这种容错算法往往性能比较好,处理较快,容忍不超过一半的故障节点。

        对于要能容忍拜占庭错误的情况,一般包括PBFT(Practical Byzantine Fault Tolerance)为代表的确定性系列算法、PoW为代表的概率算法等。而对于确定性算法,一旦达成对某个结果的共识就不可逆转,即共识是最终的结果;对于概率类的算法,共识结果则是临时的,随着时间的推移或某种强化,共识结果被推翻的概率越来越小,成为事实上的最终结果。拜占庭类容错算法往往性能较差,容忍不超过1/3的故障节点。

        此外,XFT(Cross Fault Tolerance)等最近提出的改进算法可以提供类似CFT的处理响应速度,并能在大多数节点正常工作时提供BFT保障。

注意:实践中,一致性的结果还需要客户端的额外支持,典型的情况如通过访问足够多个服务节点来比对验证,确保获得共识后的正确结果。

       3、理论界限

       科学家门证明:即便在网络通信可靠的情况下,可扩展的分布式系统的共识问题,其通用解法的理论下限是--没有下限(无解)。

      这个结论成为“FLP不可能原理”。该原来极其重要,可以看做分布式领域里的“测不准原理”。

      注意:不仅在分布式领域,实际上在很多领域都存在类似“测不准原理”的约束。

三.FLP不可能原理

      1、定义

      FLP不可能原理:在网络可靠,但允许节点失效(即便只有一个)的最小化异步模型系统中,不存在一个可以解决一致性问题的确定性的共识算法(No completely asynchronous consensus protocol can tolerate even a single unannounced process death).

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

      2、正确理解

      分布式系统中,同步与异步的含义:

      同步:是指系统中的各个环节点的始终误差存在上限;并且消息传递必须在一定时间内完成,否则认为失败;同时各个环节点完成处理消息的时间是一定的。对于同步系统,很容易判断消息是否丢失。

      异步:是指系统中的各个环节点可能存在较大的时钟差异,同时消息传输时间是任意长的,各节点对消息进行处理的时间也可能是任意长,这就造成无法判断某个消息迟迟没被响应是哪里出了问题(节点故障还是传输故障?)。不幸的是,现实生活中的系统往往都是异步系统。

FLP原来实际上说明对于允许节点失效情况下,纯粹异步系统无法确保一致性在有效时间内完成。即便对于非拜占庭错误的前提下,包括Paxos,Raft等算法也都存在无法达成共识的情况,只是在工程实践中这种情况出现的概率很小。

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

在付出一些代价的情况下,我们在共识的达成上,能做到多好?回答这个问题的是另一个很出名的原理:CAP原理。

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

四.CAP原理

    1、定义

   CAP原理:分布式计算机系统不可能同时确保以下三个特征:一致性(Consistency)、可用性(Availability)和分区容忍性(Partition),设计中往往需要弱化对某个特征的保证。

一致性:任何操作都是原子的,发生在后面的事件能看到前面事件发生导致的结果,注意这里指的是强一致性;

可用性:在有限时间里,任何失败节点都能应答请求;

分区容忍性:网络可能发生分区,即节点之间的通信不可保障。

当网络可能出现分区的时候,系统是无法同时保证一致性和可用性的。要么节点收到请求后因为没有得到其他节点的确认而不答应(牺牲可用性),要么节点只能答应非一致的结果(牺牲一致性,多数场景下)。

注意:网络分区是可能存在的,出现分区后很可能会导致发生“脑裂”,多个新出现的主节点可能会尝试关闭其它主节点。

    2、应用场景

    1)弱化一致性

     对结果一致性不敏感的应用,可以允许在新版上线后过一段时间才能最终更新成功,期间不保证一致性。例如网站静态页面内容、实时性较弱的查询类数据库等,简单分布式同步协议如Gossip,以及CouchDB、Cassandra数据库等,都为此设计的。

    2)弱可用性

对结果很敏感的应用,例如银行取款机,当系统故障时候会拒绝服务。MongoDB、Redis、MapReduce等是为此设计的。Paxos、Raft等共识算法,主要处理这些情况。在Paxos算法中,可能存在着无法提供可用结果的情形,同时允许少数节点离线。

    3)弱化分区容忍性

现实中,网络分区的出现的概率比较小,但较难完全避免。两阶段的提交算法,某些关系型数据库及Zookeeper主要考虑了这种设计。实践中,网络可以通过双通道等机制增强可靠性,达到稳定的网络通信。

五.ACID原则

   ACID原则是:Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性),用了四种特性的缩写。

ACID通常出现在分布式数据库领域。具体来说,ACID原则描述了分布式数据库需要满足的一致性需求,同时允许付出可用性的代价。

ACID特征如下:

Atomicity:每次操作是原子的,要么成功,要么失败;

Consistency:数据库状态是一致的,无中间状态;

Isolation:各种操作彼此间相互不影响;

Durability:状态的改变是持久的,不会失效。

于ACID相对的一个原则是BASE(Basic Availability,Soft-state,Eventual Consistency)原则,牺牲掉对一致性的约束(但最终实现一致性),来换取一定的可用性。

注意:ACID和BASE 看似对立,实则分别是对CAP特性的不同取舍。

六.Paxos算法与Raft算法

      Paxos问题:是指分布式系统中存在故障(crash fault),但不存在恶意(corrupt)节点的场景(即消息丢失或者重复,但无错误消息)下的共识问题。这也是分布式共识领域最为常见的问题。解决Paxos问题的算法主要是Paxos系列算法和Raft系列算法。

     1、Paxos算法

      Paxos算法,在工程角度实现了一种最大化保障分布式系统一致性(存在极小的概率无法实现一致)的机制。Paxos算法被广泛应用在Chubby、Zookeeper这样的分布式系统中。Paxos是第一个广泛应用的共识算法,其原理基于“两段提交”算法并进行泛化和扩展,通过消息传递来逐步消除系统中的不确定状态,是后来不少共识算法(如Raft,ZAB等)设计的基础。

      算法的原理是讲节点分为三种逻辑角色,在实现上同一个节点可以担任多个角色:

         1)Proposer(提案者):提出一个提案,等待大家批准(chosen)为结案(value)。系统中提案中都拥有一个自增的唯一提案号。往往由客户端担任该角色。

         2)Acceptor(接受者):负责对提案进行投票,接受(accept)提案。往往由服务端担任该角色;

         3)Learner(学习者):获取批准结果,并可以帮助传播,不参与投票过程。可能为客户端或者服务端。

      算法需要满足Safety和Liveness两方面的约束要求。实际上两个基础属性也是大部分分布式算法都该考虑的:

        1)Safety约束:保证决议(value)结果是对的,无歧义的,不会出现错误情况。

        2)Liveness约束:保证决议过程能在有限时间能完成。

      两阶段提交:

        1)准备阶段

        2)提交阶段

    2、Raft算法

       Raft算法是对Multi-Paxos的重新简化设计和实现。

      Raft算法面向多个决策达成一致的问题,分解了Leader选举、日志复制和安全方面的考虑,并通过约束减少了不确定性的状态空间。

       Raft算法三个角色:Leader(领导者)、Candidate(候选领导者)和Follower(跟随者)

       典型过程包括以下阶段:

         1)Leder选举

         2)日志同步

七.拜占庭问题与算法

           拜占庭问题(Byzantine Problem)讨论的是允许存在少数节点作恶(消息可能被伪造)场景下的一致性问题。拜占庭容错(Byzantine Fault Tolerant,BFT)算法讨论的是在拜占庭情况下对系统如何达成共识。

      1、两将军问题

      2、拜占庭问题

        对于拜占庭问题来说,假如节点数为N,叛变将军数为F,则N≧3F+1时,问题才有解决,由BFT算法进行保证。能确保达成一致的拜占庭系统节点数至少为4,此时最多允许出现1个坏的节点。

      3、拜占庭容错算法

       拜占庭容错算法(Byzantine Fault Tolenrant,BFT)是面向拜占庭问题的容错算法,解决的是在网络通信可靠但节点可能故障的情况下如何达成共识。

        PBFT(Practical Byzantine Fault Tolenrant)算法,可以在失效节点不超过总数1/3的情况下同时保障Safety和Liveness。该算法采用密码学相关技术(RSA签名算法、消息验证编码和摘要)确保消息传递过程无法被篡改和破坏。

        算法基本过程如下:

            1)首先通过轮回或者随机算法选出某个节点为主节点,此后只要主节点不切换,则成为一个试图(View);

            2)在某个视图中,客户端将请求<REQUEST,operation,timestamp,client>发送给主节点,主节点负责广播请求到所有其它副本节点;

           3)所有节点处理完请求,将处理结果<REPLY,view,timpstamp,client,id_node,response>返回给客户端。客户端检查是否收到了至少 f+1 个来自不同节点的相同结果,作为最终结果。

        主节点广播过程包括三个阶段的处理:预准备(pre-prepare)阶段、准备(prepare)阶段和提交(commit)阶段。预准备和准备阶段确保在同一个视图内请求发送的顺序正确;准备和提交阶段则确保在不同视图之间的确认请求是保存的:

           1)预准备阶段:主节点为从客户端收到的请求分配提案编号,然后发出预准备消息<<PRE-PREPARE,view,n,digest>>给副本节点,其中message是客户端的请求消息,digest是消息的摘要;

          2)准备阶段:副节点收到预准备消息后,检查消息合法,如检查通过则向其它节点发送准备消息<PREPARE,view,n,digest,id>带上自己的id信息,同时接收来自其他节点的准备消息。收到准备消息的节点对消息同样进行合法性检查。验证通过则把这个消息写入消息日志中。集齐2f+1个验证过的消息才进入准备状态;

         3)提交阶段:广播commit消息,告诉其他节点某个提案n在视图v里已处于准备状态。如果集齐至少2f+1个验证过的commit消息,则说明提案通过。

       4、新的解决思路

         拜占庭问题之所以难解,在于任何时候系统中都可能存在多个提案(因为提案成本很低),并且要完成最终一致性确认过程是否复杂,容易受干扰。

        比特币的区块链网络在设计时提出了创新的PoW(Proof of Work)概率算法思路,针对这两个环节进行改进。

        首先,限制一段时间内整个网络中出现提案的个数(通过增加提案成本);其次是放宽对最终一致性确认的需求,约定好大家都确认并沿着已知最长的链进行拓展。系统的最终确认是概率意义上的存在。这样,即使有人试图恶意破坏,也会付出相应的经济代价(超过整个系统一半的计算力)。

         后来的各种PoX系列算法,也是沿着这个思路改进的,采用经济上的惩罚来制约破坏者。

八.可靠性指标

         可靠性(availability),或者说可用性,是描述系统可以提供服务能力的重要指标。

         服务的可用性可用用服务承诺(Service Level Agreement,SLA)、服务指标(Service Level Indicator,SLI)、服务目标(Service Level Objective,SLO)等方面进行衡量。

         1、几个9的指标

              5个9,电信级别,每年允许不可用时间 5分钟;

              4个9,云计算平台,每年允许不可用时间51.6分钟

              3个9,普通企业系统,每年允许不可用时间8.6小时

          2、2个核心时间

           MTBF(Mean Time Between Failures):平均故障间隔时间,即系统可以无故障运行的预期时间;

           MTTR(Mean Time to Repair):平均修复时间,即发生故障后,系统可以恢复到正常运行的预期时间;

           MTBF衡量了系统发生故障的频率,如果一个系统的MTBF很短,则往往意味着该系统可用性低;

           MTTF则反映了系统碰到故障后服务的恢复能力,如果系统的MTTR过长,则说明系统一旦发生故障,需要较长时间才能恢复服务。

          一个高可用的的系统应该具有尽量长的MTBF和尽量短的MTTR。

          3、提高可靠性

         提高系统可靠性的两个思路:一是让系统中的单个组件都变的更可靠;而是干脆消灭单点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值