节点
在具体的工程项目中,一个节点每每是一个操做系统上的进程。在本文的模型中,认为节点是一个完整的、不可分的总体,若是某个程序进程实际上由若干相对独立部分构成,则在模型中能够将一个进程划分为多个节点。
异常php
1.机器宕机:机器宕机是最多见的异常之一。在大型集群中每日宕机发生的几率为千分之一左右,在实践中,一台宕机的机器恢复的时间一般认为是24 小时,通常须要人工介入重启机器。node
2.网络异常:消息丢失,两片节点之间彼此彻底没法通讯,即出现了“网络分化”;算法
消息乱序,有必定的几率不是按照发送时的顺序依次到达目的节点,考虑使用序列号等机制处理网络消息的乱序问题,使得无效的、过时的网络消息不影响系统的正确性;数据库
数据错误;不可靠的TCP,TCP 协议为应用层提供了可靠的、面向链接的传输服务,但在分布式系统的协议设计中不能认为全部网络通讯都基于TCP 协议则通讯就是可靠的。缓存
TCP协议只能保证同一个TCP 连接内的网络消息不乱序,TCP 连接之间的网络消息顺序则没法保证。安全
3.分布式三态:若是某个节点向另外一个节点发起RPC(Remote procedure call)调用,即某个节点A 向另外一个节点B 发送一个消息,节点B 根据收到的消息内容完成某些操做,并将操做的结果经过另外一个消息返回给节点A,那么这个RPC 执行的结果有三种状态:“成功”、“失败”、“超时(未知)”,称之为分布式系统的三态。服务器
4.存储数据丢失:对于有状态节点来讲,数据丢失意味着状态丢失,一般只能从其余节点读取、恢复存储的状态。网络
5.异常处理原则:被大量工程实践所检验过的异常处理黄金原则是:任何在设计阶段考虑到的异常状况必定会在系统实际运行中发生,但在系统实际运行遇到的异常却颇有可能在设计时未能考虑,因此,除非需求指标容许,在系统设计时不能放过任何异常状况。session
副本(replica/copy)指在分布式系统中为数据或服务提供的冗余。对于数据副本指在不一样的节点上持久化同一份数据,当出现某一个节点的存储的数据丢失时,能够从副本上读到数据。数据结构
数据副本是分布式系统解决数据丢失异常的惟一手段。另外一类副本是服务副本,指数个节点提供某种相同的服务,这种服务通常并不依赖于节点的本地存储,其所需数据通常来自其余节点。
副本协议是贯穿整个分布式系统的理论核心。
副本一致性
分布式系统经过副本控制协议,使得从系统外部读取系统内部各个副本的数据在必定的约束条件下相同,称之为副本一致性(consistency)。副本一致性是针对分布式系统而言的,不是针对某一个副本而言。
1.强一致性(strong consistency):任什么时候刻任何用户或节点均可以读到最近一次成功更新的副本数据。强一致性是程度最高的一致性要求,也是实践中最难以实现的一致性。
2.单调一致性(monotonic consistency):任什么时候刻,任何用户一旦读到某个数据在某次更新后的值,这个用户不会再读到比这个值更旧的值。
单调一致性是弱于强一致性却很是实用的一种一致性级别。由于一般来讲,用户只关心从己方视角观察到的一致性,而不会关注其余用户的一致性状况。
3.会话一致性(session consistency):任何用户在某一次会话内一旦读到某个数据在某次更新后的值,这个用户在此次会话过程当中不会再读到比这个值更旧的值。
会话一致性经过引入会话的概念,在单调一致性的基础上进一步放松约束,会话一致性只保证单个用户单次会话内数据的单调修改,对于不一样用户间的一致性和同一用户不一样会话间的一致性没有保障。
实 践中有许多机制正好对应会话的概念,例如php 中的session 概念。
4.最终一致性(eventual consistency):最终一致性要求一旦更新成功,各个副本上的数据最终将达 到彻底一致的状态,但达到彻底一致状态所须要的时间不能保障。
对于最终一致性系统而言,一个用户只要始终读取某一个副本的数据,则能够实现相似单调一致性的效果,但一旦用户更换读取的副本,则没法保障任何一致性。
5.弱一致性(week consistency):一旦某个更新成功,用户没法在一个肯定时间内读到此次更新的值,且即便在某个副本上读到了新的值,也不能保证在其余副本上能够读到新的值。
弱一致性系统通常很难在实际中使用,使用弱一致性系统须要应用方作更多的工做从而使得系统可用。
1.性能:系统的吞吐能力,指系统在某一时间能够处理的数据总量,一般能够用系统每秒处理的总的数据量来衡量;
系统的响应延迟,指系统完成某一功能须要使用的时间;
系统的并发能力,指系统能够同时完成某一功能的能力,一般也用QPS(query per second)来衡量。
上述三个性能指标每每会相互制约,追求高吞吐的系统,每每很难作到低延迟;系统平均响应时间较长时,也很难提升QPS。
2.可用性:系统的可用性(availability)指系统在面对各类异常时能够正确提供服务的能力。
系统的可用性能够用系统停服务的时间与正常服务的时间的比例来衡量,也能够用某功能的失败次数与成功次数的比例来衡量。可用性是分布式的重要指标,衡量了系统的鲁棒性,是系统容错能力的体现。
3.可扩展性:系统的可扩展性(scalability)指分布式系统经过扩展集群机器规模提升系统性能(吞吐、延迟、并发)、存储容量、计算能力的特性。好的分布式系统总在追求“线性扩展性”,也就是使得系统的某一指标能够随着集群中的机器数量线性增加。
4.一致性:分布式系统为了提升可用性,老是不可避免的使用副本的机制,从而引起副本一致性的问题。越是强的一致的性模型,对于用户使用来讲使用起来越简单。
2.1 数据分布方式
所谓分布式系统顾名思义就是利用多台计算机协同解决单台计算机所不能解决的计算、存储等问题。
单机系统与分布式系统的最大的区别在于问题的规模,即计算、存储的数据量的区别。
将一个单机问题使用分布式解决,首先要解决的就是如何将问题拆解为可使用多机分布式解决,使得分布式系统中的每台机器负责原问题的一个子集。因为不管是计算仍是存储,其问题输入对象都是数据,因此如何拆解分布式系统的输入数据成为分布式系统的基本问题。
哈希方式
哈希分布数据的缺点一样明显,突出表现为可扩展性不高,一旦集群规模须要扩展,则几乎全部的数据须要被迁移并从新分布。工程中,扩展哈希分布数据的系统时,每每使得集群规模成倍扩展,按照数据从新计算哈希,这样本来一台机器上的数据只需迁移一半到另外一台对应的机器上便可完成扩展。
针对哈希方式扩展性差的问题,一种思路是再也不简单的将哈希值与机器作除法取模映射,而是将对应关系做为元数据由专门的元数据服务器管理.同时,哈希值取模个数每每大于机器个数,这样同一台机器上须要负责多个哈希取模的余数。但须要以较复杂的机制维护大量的元数据。哈希分布数据的另外一个缺点是,一旦某数据特征值的数据严重不均,容易出现“数据倾斜”(data skew)问题。
哈希分布数据的另外一个缺点是,一旦某数据特征值的数据严重不均,容易出现“数据倾斜”(data skew)问题
按数据范围分布
按数据范围分布是另外一个常见的数据分布式,将数据按特征值的值域范围划分为不一样的区间,使得集群中每台(组)服务器处理不一样区间的数据。
工程中,为了数据迁移等负载均衡操做的方便,每每利用动态划分区间的技术,使得每一个区间中服务的数据量尽可能的同样多。当某个区间的数据量较大时,经过将区间“分裂”的方式拆分为两个区间,使得每一个数据区间中的数据量都尽可能维持在一个较为固定的阈值之下。
通常的,每每须要使用专门的服务器在内存中维护数据分布信息,称这种数据的分布信息为一种元信息。甚至对于大规模的集群,因为元信息的规模很是庞大,单台 计算机没法独立维护,须要使用多台机器做为元信息服务器。
按数据量分布
数据量分布数据与具体的数据特征无关,而是将数据视为一个顺序增加的文件,并将这个文件按照某一较为固定的大小划分为若干数据块(chunk),不一样的数据块分布到不一样的服务器上
与按数据范围分布数据的方式相似的是,按数据量分布数据也须要记录数据块的具体分布状况,并将该分布信息做为元数据使用元数据服务器管理。
因为与具体的数据内容无关,按数据量分布数据的方式通常没有数据倾斜的问题,数据老是被均匀切分并分布到集群中。
当集群须要从新负载均衡时,只需经过迁移数据块便可完成。集群扩容也没有太大的限制,只需将部分数据库迁移到新加入的机器上便可以完成扩容。
按数据量划分数据的缺点是须要管理较为复杂的元信息,与按范围分布数据的方式相似,当集群规模较大时,元信息的数据量也变得很大,高效的管理元信息成为新的课题。
一致性哈希
一致性哈希(consistent hashing)是另外一个种在工程中使用较为普遍的数据分布方式。一致性哈希最初在P2P 网络中做为分布式哈希表(DHT)的经常使用数据分布算法。
一致性哈希的基本方式是使用一个哈希函数计算数据或数据特征的哈希值,令该哈希函数的输出值域为一个封闭的环,即哈希函数输出的最大值是最小值的前序。将节点随机分布到这个环上,每一个节点负责处理从本身开始顺时针至下一个节点的所有哈希值域上的数据。
使用一致性哈希的方式须要将节点在一致性哈希环上的位置做为元信息加以管理,这点比直接使用哈希分布数据的方式要复杂。然而,节点的位置信息只于集群中的机器规模相关,其元信息的量一般比按数据范围分布数据和按数据量分布数据的元信息量要小不少。
为此一种常见的改进算法是引入虚节点(virtual node)的概念,系统初始时就建立许多虚节点,虚节点的个数通常远大于将来集群中机器的个数,将虚节点均匀分布到一致性哈希值域环上,其功能与基本一致性哈希算法中的节点相同。为每一个节点分配若干虚节点。
操做数据时,首先经过数据的哈希值在环上找到对应的虚节点,进而查找元数据找到对应的真实节点。使用虚节点改进有多个优势。
首先,一旦某个节点不可用,该节点将使得多个虚节点不可用,从而使得多个相邻的真实节点负载失效节点的压里。同理,一旦加入一个新节点,能够分配多个虚节点,从而使得新节点能够 负载多个原有节点的压力,从全局看,较容易实现扩容时的负载均衡。
副本与数据分布
分布式系统容错、提升可用性的基本手段就是使用副本。对于数据副本的分布方式主要影响系统的可扩展性。一种基本的数据副本策略是以机器为单位,若干机器互为副本,副本机器之间的数据彻底相同。这种策略适用于上述各类数据分布方式。其优势是很是简单,其缺点是恢复数据的效率不高、可扩展性也不高。
更合适的作法不是以机器做为副本单位,而是将数据拆为较合理的数据段,以数据段为单位做为副本。
实践中,经常使得每一个数据段的大小尽可能相等且控制在必定的大小之内。数据段有不少不一样的称谓,segment,fragment,chunk,partition 等等。数据段的选择与数据分布方式直接相关。
对于哈希分数据的方式,每一个哈希分桶后的余数能够做为一个数据段,为了控制数据段的大小,经常使得分桶个数大于集群规模。一旦将数据分为数据段,则能够以数据段为单位管理副本,从而副本与机器再也不硬相关,每台机器均可以负责必定数据段的副本。
一旦副本分布与机器无关,数据丢失后的恢复效率将很是高。这是由于,一旦某台机器的数据丢失,其上数据段的副本将分布在整个集群的全部机器中,而不是仅在几个副本机器中,从而能够从整个集群同时拷贝恢复数据,而集群中每台数据源机器均可以以很是低的资源作拷贝。做为恢复数据源的机器即便都限速1MB/s,如有100 台机器参与恢复,恢复速度也能达到100MB/s。
再者,副本分布与机器无关也利于集群容错。若是出现机器宕机,因为宕机机器上的副本分散于整个集群,其压力也天然分散到整个集群。
最后,副本分布与机器无关也利于集群扩展。理论上,设集群规模 为N 台机器,当加入一台新的机器时,只需从各台机器上迁移1/N – 1/N+1 比例的数据段到新机器即实现了新的负载均衡。因为是从集群中各机器迁移数据,与数据恢复同理,效率也较高。
工程中,彻底按照数据段创建副本会引发须要管理的元数据的开销增大,副本维护的难度也相应增大。一种折中的作法是将某些数据段组成一个数据段分组,按数据段分组为粒度进行副本管理。这样作能够将副本粒度控制在一个较为合适的范围内。
本地化计算
在分布式系统中,数据的分布方式也深深影响着计算的分布方式。在分布式系统中计算节点和保存计算数据的存储节点能够在同一台物理机器上,也能够位于不一样的物理机器。
若是计算节点和存储节点位于不一样的物理机器则计算的数据须要经过网络传输,此种方式的开销很大,甚至网络带宽会成为系统的整体瓶颈。
另外一种思路是,将计算尽可能调度到与存储节点在同一台物理机器上的计算节点上进行,这称之为本地化计算。本地化计算是计算调度的一种重要优化,其体现了一种重要的分布式调度思想:“移动数据不如移动计算”。
数据分布方式的选择
在实际工程实践中,能够根据需求及实施复杂度合理选择数据分布方式。另外,数据分布方式是能够灵活组合使用的,每每能够兼备各类方式的优势,收到较好的综合效果。
例:数据倾斜问题,在按哈希分数据的基础上引入按数据量分布数据的方式,解决该数据倾斜问题。按用户id 的哈希值分数据,当某个用户id 的数据量特别大时,该用户的数据始终落在某一台机器上。此时,引入按数据量分布数据的方式,统计用户的数据量,并按某一阈值将用户的数据切为多个均匀的数据段,将这些数据段分布到集群中去。因为大部分用户的数据量不会超过阈值,因此元数据中仅仅保存超过阈值的用户的数据段分布信息,从而能够控制元数据的规模。这种哈希分布数据方式与按数据量分布数据方式组合使用的方案,在某真实系统中使用,取得了较好的效果。
副本控制协议指按特定的协议流程控制副本数据的读写行为,使得副本知足必定的可用性和一致性要求的分布式协议。副本控制协议要具备必定的对抗异常状态的容错能力,从而使得系统具备必定的可用性,同时副本控制协议要能提供必定一致性级别。由CAP 原理(在2.9 节详细分析)可知,要设计一种知足强一致性,且在出现任何网络异常时均可用的副本协议是不可能的。为此,实际中的副本控制协议老是在可用性、一致性与性能等各要素之间按照具体需求折中。
副本控制协议能够分为两大类:“中心化(centralized)副本控制协议”和“去中心化(decentralized)副本控制协议”。
中心化副本控制协议
中心化副本控制协议的基本思路是由一个中心节点协调副本数据的更新、维护副本之间的一致性。
图给出了中心化副本协议的通用架构。中心化副本控制协议的优势是协议相对较为简单,全部的副本相关的控制交由中心节点完成。并发控制将由中心节点完成,从而使得一个分布式并发控制问题,简化为一个单机并发控制问题。
所谓并发控制,即多个节点同时须要修改副本数据时,须要解决“写写”、“读写”等并发冲突。单机系统上经常使用加锁等方式进行并发控制。对于分布式并发控制,加锁也是一个经常使用的方法,但若是没有中心节点统一进行锁管理,就须要彻底分布式化的锁系统,会使得协议很是复杂。
中心化副本控制协议的缺点是系统的可用性依赖于中心化节点,当中心节点异常或与中心节点通讯中断时,系统将失去某些服务(一般至少失去更新服务),因此中心化副本控制协议的缺点正是存在必定的停服务时间。
primary-secondary 协议
在primary-secondary 类型的协议中,副本被分为两大类,其中有且仅有一个副本做为primary 副本,除primary 之外的副本都做为secondary 副本。维护primary 副本的节点做为中心节点,中心节点负责维护数据的更新、并发控制、协调副本的一致性。
Primary-secondary 类型的协议通常要解决四大类问题:数据更新流程、数据读取方式、Primary 副本的肯定和切换、数据同步(reconcile)。
数据更新基本流程
1.数据更新都由primary 节点协调完成。
2.外部节点将更新操做发给primary 节点
3.primary 节点进行并发控制即肯定并发更新操做的前后顺序
4.primary 节点将更新操做发送给secondary 节点
5.primary 根据secondary 节点的完成状况决定更新是否成功并将结果返回外部节点
在工程实践中,若是由primary 直接同时发送给其余N 个副本发送数据,则每一个 secondary 的更新吞吐受限于primary 总的出口网络带宽,最大为primary 网络出口带宽的1/N。
为了解决这个问题,有些系统(例如,GFS),使用接力的方式同步数据,即primary 将更新发送给第一 个secondary 副本,第一个secondary 副本发送给第二secondary 副本,依次类推。
数据读取方式
数据读取方式也与一致性高度相关。若是只须要最终一致性,则读取任何副本均可以知足需求。
若是须要会话一致性,则能够为副本设置版本号,每次更新后递增版本号,用户读取副本时验证版本号,从而保证用户读到的数据在会话范围内单调递增。使用primary-secondary 比较困难的是实现强一致性。
因为数据的更新流程都是由primary 控制的,primary 副本上的数据必定是最新的,因此 若是始终只读primary 副本的数据,能够实现强一致性。若是只读primary 副本,则secondary 副本将不提供读服务。
实践中,若是副本不与机器绑定,而是按照数据段为单位维护副本,仅有primary 副本提供读服务在不少场景下并不会造出机器资源浪费。
将副本分散到集群中个,假设primary 也是随机的肯定的,那么每台机器上都有一些数据的primary 副本,也有另外一些数据段的secondary 副本。从而某台服务器实际都提供读写服务。
由primary 控制节点secondary 节点的可用性。当primary 更新某个secondary 副本不成功时,primary 将该secondary 副本标记为不可用,从而用户再也不读取该不可用的副本。不可用的 secondary 副本能够继续尝试与primary 同步数据,当与primary 完成数据同步后,primary 能够副本标记为可用。
这种方式使得全部的可用的副本,不管是primary 仍是secondary 都是可读的,且在一个肯定的时间内,某secondary 副本要么更新到与primary 一致的最新状态,要么被标记为不可用,从而符合较高的一致性要求。这种方式依赖于一个中心元数据管理系统,用于记录哪些副本可用,哪些副本不可用。某种意义上,该方式经过下降系统的可用性来提升系统的一致性。
primary 副本的肯定与切换
在primary-secondary 类型的协议中,另外一个核心的问题是如何肯定primary 副本,尤为是在原primary 副本所在机器出现宕机等异常时,须要有某种机制切换primary 副本,使得某个secondary 副本成为新的primary 副本。
一般的,在primary-secondary 类型的分布式系统中,哪一个副本是primary 这一信息都属于元信息,由专门的元数据服务器维护。执行更新操做时,首先查询元数据服务器获取副本的primary 信息,从而进一步执行数据更新流程。
因为分布式系统中可靠的发现节点异常是须要必定的探测时间的,这样的探测时间一般是10 秒级别,这也意味着一旦primary 异常,最多须要10 秒级别的发现时间,系统才能开始primary 的切换,在这10 秒时间内,因为没有primary,系统不能提供更 新服务,若是系统只能读primary 副本,则这段时间内甚至不能提供读服务。从这里能够看到,primary-backup 类副本协议的最大缺点就是因为primary 切换带来的必定的停服务时间。
数据同步
不一致的secondary 副本须要与primary 进行同步(reconcile)。
一般不一致的形式有三种:
1、因为网络分化等异常,secondary 上的数据落后于primary 上的数据。
2、在某些协议下,secondary 上的数据有多是脏数据,须要被丢弃。所谓脏数据是因为primary 副本没有进行某一更新操做,而secondary 副本上反而进行的多余的修改操做,从而形成secondary 副本数据错误。
3、secondary 是一个新增长的副本,彻底没有数据,须要从其余副本上拷贝数据。
对于第一种secondary 数据落后的状况,常见的同步方式是回放primary 上的操做日志(一般是redo 日志),从而追上primary 的更新进度。
对于脏数据的状况,较好的作法是设计的分布式协议不产生脏数据。若是协议必定有产生脏数据的可能,则也应该使得产生脏数据的几率降到很是低得状况,从而一旦发生脏数据的状况能够简单的直接丢弃有脏数据的副本,这样至关于副本没有数据。
另外,也能够设计一些基于undo 日志的方式从而能够删除脏数据。若是secondary 副本彻底没有数据,则常见的作法是直接拷贝primary 副本的数据,这种方法每每比回放日志追更新进度的方法快不少。但拷贝数据时primary 副本须要可以继续提供更新服务,这就要求primary 副本支持快照(snapshot)功能。即对某一刻的副本数据造成快照,而后拷贝快照,拷贝完成后使用回放日志的方式追快照造成后的更新操做。
去中心化副本控制协议
去中心化副本控制协议没有中心节点,协议中全部的节点都是彻底对等的,节点之间经过平等协商达到一致。从而去中心化协议没有由于中心化节点异常而带来的停服务等问题。
去中心化协议的最大的缺点是协议过程一般比较复杂。尤为当去中心化协议须要实现强一致性时,协议流程变得复杂且不容易理解。因为流程的复杂,去中心化协议的效率或者性能通常也较中心化协议低。一个不恰当的比方就是,中心化副本控制协议相似专制制度,系统效率高但高度依赖于中心节点,一旦中心节点异常,系统受到的影响较大;去中心化副本控制协议相似民主制度,节点集体协商,效率低下,但个别节点的异常不会对系统整体形成太大影响。
Lease 机制是最重要的分布式协议,普遍应用于各类实际的分布式系统中。
基于lease 的分布式cache 系统
基本的问题背景以下:在一个分布式系统中,有一个中心服务器节点,中心服务器存储、维护着一些数据,这些数据是系统的元数据。系统中其余的节点经过访问中心服务器节点读取、修改其上的元数据。
因为系统中各类操做都依赖于元数据,若是每次读取元数据的操做都访问中心服务器 节点,那么中心服务器节点的性能成为系统的瓶颈。为此,设计一种元数据cache,在各个节点上 cache 元数据信息,从而减小对中心服务器节点的访问,提升性能。
另外一方面,系统的正确运行严格依赖于元数据的正确,这就要求各个节点上cache 的数据始终与中心服务器上的数据一致,cache 中的数据不能是旧的脏数据。最后,设计的cache 系统要能最大可能的处理节点宕机、网络中断等异常,最大程度的提升系统的可用性。
为此,利用lease 机制设计一套cache 系统,其基本原理为以下。
中心服务器在向各节点发送数据时同时向节点颁发一个lease。每一个lease 具备一个有效期,和信用卡上的有效期相似,lease 上的 有效期一般是一个明确的时间点,例如12:00:10,一旦真实时间超过这个时间点,则lease 过时失效。这样lease 的有效期与节点收到lease 的时间无关,节点可能收到lease 时该lease 就已通过期失效。这里首先假设中心服务器与各节点的时钟是同步的,在下节中讨论时钟不一样步对lease 的影响。
中心服务器发出的lease 的含义为:在lease 的有效期内,中心服务器保证不会修改对应数据的值。所以,节点收到数据和lease 后,将数据加入本地Cache,一旦对应的lease 超时,节点将对应的本地cache 数据删除。中心服务器在修改数据时,首先阻塞全部新的读请求,并等待以前为该数据发出的全部lease 超时过时,而后修改数据的值。
基于lease 的cache,客户端节点读取元数据
1.判断元数据是否已经处于本地cache 且lease 处于有效期内1.1 是:直接返回cache 中的元数据1.2 否:向中心服务器节点请求读取元数据信息1.2.1 服务器收到读取请求后,返回元数据及一个对应的lease 1.2.2 客户端是否成功收到服务器返回的数据 1.2.2.1 失败或超时:退出流程,读取失败,可重试1.2.2.2 成功:将元数据与该元数据的lease 记录到内存中,返回元数据
2.基于lease 的cache,客户端节点修改元数据流程2.1 节点向服务器发起修改元数据请求。2.2 服务器收到修改请求后,阻塞全部新的读数据请求,即接收读请求,但不返回数据。2.3 服务器等待全部与该元数据相关的lease 超时。2.4 服务器修改元数据并向客户端节点返回修改为功。
上述机制能够保证各个节点上的cache 与中心服务器上的中心始终一致。这是由于中心服务器节点在发送数据的同时授予了节点对应的lease,在lease 有效期内,服务器不会修改数据,从而客户端节点能够放心的在lease 有效期内cache 数据。
上述lease 机制能够容错的关键是:服务器一旦 发出数据及lease,不管客户端是否收到,也不管后续客户端是否宕机,也不管后续网络是否正常,服务器只要等待lease 超时,就能够保证对应的客户端节点不会再继续cache 数据,从而能够放心的修改数据而不会破坏cache 的一致性。
上述基础流程有一些性能和可用性上的问题,但能够很容易就优化改性。优化点一:服务器在修改元数据时首先要阻塞全部新的读请求,形成没有读服务。这是为了防止发出新的lease 从而引发不断有新客户端节点持有lease 并缓存着数据,造成“活锁”。优化的方法很简单,服务器在进入修改数据流程后,一旦收到读请求则只返回数据但不颁发lease。
从而形成在修改流程执行的过程当中,客户端能够读到元数据,只是不能缓存元数据。进一步的优化是,当进入修改流程,服务器颁发的lease 有效期限选择为已发出的lease 的最大有效期限。这样作,客户端能够继续在服务器进入修改流程后继续缓存元数据,但服务器的等待全部lease 过时的时间也不会由于颁发新的lease 而不断延长。
最后,=cache 机制与多副本机制的区别。Cache 机制与多副本机制的类似之处都 是将一份数据保存在多个节点上。但Cache 机制却要简单许多,对于cache 的数据,能够随时删除丢弃,并命中cache 的后果仅仅是须要访问数据源读取数据;然而副本机制却不同,副本是不能随意丢弃的,每失去一个副本,服务质量都在降低,一旦副本数降低到必定程度,则每每服务将再也不可用。
lease 机制的分析
lease 的定义:Lease 是由颁发者授予的在某一有效期内的承诺。颁发者一旦发出lease,则不管接受方是否收到,也不管后续接收方处于何种状态,只要lease 不过时,颁发者必定严守承诺;另外一方面,接收方在lease 的有效期内可使用颁发者的承诺,但一旦lease 过时,接收方必定不能继续使用颁发者的承诺。
Lease 机制具备很高的容错能力。首先,经过引入有效期,Lease 机制可否很是好的容错网络异常。Lease 颁发过程只依赖于网络能够单向通讯,即便接收方没法向颁发者发送消息,也不影响lease 的颁发。
因为lease 的有效期是一个肯定的时间点,lease 的语义与发送lease 的具体时间无关,因此 同一个lease 能够被颁发者不断重复向接受方发送。即便颁发者偶尔发送lease 失败,颁发者也能够 简单的经过重发的办法解决。一旦lease 被接收方成功接受,后续lease 机制再也不依赖于网络通讯,即便网络彻底中断lease 机制也不受影响。
再者,Lease 机制能较好的容错节点宕机。若是颁发者宕机,则宕机的颁发者一般没法改变以前的承诺,不会影响lease 的正确性。在颁发者机恢复后,若是颁发者恢复出了以前的lease 信息,颁发者能够继续遵照lease 的承诺。若是颁发者没法恢复lease 信息,则只需等待一个最大的lease 超时时间就可使得全部的lease 都失效,从而不破坏lease机制。
例如上节中的cache 系统的例子中,一旦服务器宕机,确定不会修改元数据,从新恢复后,只需等待一个最大的lease 超时时间,全部节点上的缓存信息都将被清空。
对于接受方宕机的状况,颁发者 不须要作更多的容错处理,只需等待lease 过时失效,就能够收回承诺,实践中也就是收回以前赋予的权限、身份等。最后,lease 机制不依赖于存储。颁发者能够持久化颁发过的lease 信息,从而在 宕机恢复后可使得在有效期的lease 继续有效。但这对于lease 机制只是一个优化,如以前的分析,即便颁发者没有持久化lease 信息,也能够经过等待一个最大的lease 时间的方式使得以前全部颁发 的lease 失效,从而保证机制继续有效。
Lease 机制依赖于有效期,这就要求颁发者和接收者的时钟是同步的。一方面,若是颁发者的 时钟比接收者的时钟慢,则当接收者认为lease 已通过期的时候,颁发者依旧认为lease 有效。接收者能够用在lease 到期前申请新的lease 的方式解决这个问题。另外一方面,若是颁发者的时钟比接收 者的时钟快,则当颁发者认为lease 已通过期的时候,接收者依旧认为lease 有效,颁发者可能将lease 颁发给其余节点,形成承诺失效,影响系统的正确性。对于这种时钟不一样步,实践中的一般作法是将颁发者的有效期设置得比接收者的略大,只需大过期钟偏差就能够避免对lease 的有效性的影响。
基于lease 机制肯定节点状态
分布式协议依赖于对节点状态认知的全局一致性,即一旦节点Q 认为某个节点 A 异常,则节点A 也必须认为本身异常,从而节点A 中止做为primary,避免“双主”问题的出现。
解决这种问题有两种思路,第1、设计的分布式协议能够容忍“双主”错误,即不依赖于对节点状 态的全局一致性认识,或者全局一致性状态是全体协商后的结果;
第2、利用lease 机制。对于第一 种思路即放弃使用中心化的设计,而改用去中心化设计,超过本节的讨论范畴。下面着重讨论利用 lease 机制肯定节点状态。
由中心节点向其余节点发送lease,若某个节点持有有效的lease,则认为该节点正常能够提供服 务。用于例2.3.1 中,节点A、B、C 依然周期性的发送heart beat 报告自身状态,节点Q 收到heart beat 后发送一个lease,表示节点Q 确认了节点A、B、C 的状态,并容许节点在lease 有效期内正常工 做。节点Q 能够给primary 节点一个特殊的lease,表示节点能够做为primary 工做。一旦节点Q 但愿切换新的primary,则只需等前一个primary 的lease 过时,则就能够安全的颁发新的lease 给新的 primary 节点,而不会出现“双主”问题。
在实际系统中,若用一个中心节点发送lease 也有很大的风险,一旦该中心节点宕机或网络异常,则全部的节点没有lease,从而形成系统高度不可用。为此,实际系统老是使用多个中心节点互为副本,成为一个小的集群,该小集群具备高可用性,对外提供颁发lease 的功能。chubby 和zookeeper 都是基于这样的设计。
lease 的有效期时间选择
工程中,常选择的lease 时长是10 秒级别,这是一个通过验证的经验值,实践中能够做为参考并综合选择合适的时长。
先作这样的约定:更新操做(write)是一系列顺序的过程,经过其余机制肯定更新操做的顺序(例如primary-secondary 架构中由primary 决定顺序),每一个更新操做记为wi, i 为更新操做单调递增的序号,每一个wi 执行成功后副本数据都发生变化,称为不一样的数据版本,记 做vi。假设每一个副本都保存了历史上全部版本的数据。
write-all-read-one
Write-all-read-one(简称WARO)是一种最简单的副本控制规则,顾名思义即在更新时写全部的副本,只有在全部的副本上更新成功,才认为更新成功,从而保证全部的副本一致,这样在读取数据时能够读任一副本上的数据。
因为更新操做须要在全部的N 个副本上都成功,更新操做才能成 功,因此一旦有一个副本异常,更新操做失败,更新服务不可用。对于更新服务,虽然有N 个副本, 但系统没法容忍任何一个副本异常。另外一方面,N 个副本中只要有一个副本正常,系统就能够提供读服务。对于读服务而言,当有N 个副本时,系统能够容忍N-1 个副本异常。从上述分析能够发现WARO 读服务的可用性较高,但更新服务的可用性不高,甚至虽然使用了副本,但更新服务的可用性等效于没有副本。
Quorum 定义
在Quorum 机制下,当某次更新操做wi 一旦在全部N 个副本中的W 个副本上都成功,则就称 该更新操做为“成功提交的更新操做”,称对应的数据为“成功提交的数据”。令R>N-W,因为更新 操做wi 仅在W 个副本上成功,因此在读取数据时,最多须要读取R 个副本则必定能读到wi 更新后 的数据vi 。若是某次更新wi 在W 个副本上成功,因为W+R>N,任意R 个副本组成的集合必定与 成功的W个副本组成的集合有交集,因此读取R 个副本必定能读到wi 更新后的数据vi。
某系统有5 个副本,W=3,R=3,最初5 个副本的数据一致,都是v1,某次更新操做 w2 在前3 副本上成功,副本状况变成(v2 v2 v2 v1 v1)。
此时,任意3 个副本组成的集合中必定包括 v2。在上述定义中,令W=N,R=1,就获得WARO,即WARO 是Quorum 机制的一种特例。与分析WARO 类似,分析Quorum 机制的可用性。限制Quorum 参数为W+R=N+1。因为更新 操做须要在W 个副本上都成功,更新操做才能成功,因此一旦N-W+1 个副本异常,更新操做始终没法在W 个副本上成功,更新服务不可用。
另外一方面,一旦N-R+1 个副本异常,则没法保证必定能够读到与W 个副本有交集的副本集合,则读服务的一致性降低。
再次强调:仅仅依赖quorum 机制是没法保证强一致性的。由于仅有quorum 机制时没法肯定最新已成功提交的版本号,除非将最新已提交的版本号做为元数据由特定的元数据服务器或元数据集群管理,不然很难肯定最新成功提交的版本号。在下一节中,将讨论在哪些状况下,能够仅仅 经过quorum 机制来肯定最新成功提交的版本号。
Quorum 机制的三个系统参数N、W、R 控制了系统的可用性,也是系统对用户的服务承诺:数据最多有N 个副本,但数据更新成功W 个副本即返回用户成功。对于一致性要求较高的Quorum 系统,系统还应该承诺任什么时候候不读取未成功提交的数据,即读取到的数据都是曾经在W 个副本上成功的数据。
读取最新成功提交的数据
Quorum 机制只需成功更新N 个副本中的W 个,在读取R 个副本时,必定能够读到最新的成功提交的数据。但因为有不成功的更新状况存在,仅仅读取R 个副本却不必定能肯定哪一个版本的数据 是最新的已提交的数据。对于一个强一致性Quorum 系统,若存在个数据少于W 个,假设为X 个,则继续读取其余副本,直若成功读取到W 个 该版本的副本,则该数据为最新的成功提交的数据;若是在全部副本中该数据的个数确定不满 足W 个,则R 中版本号第二大的为最新的成功提交的副本。
例:在读取到(v2 v1 v1)时,继续读取剩余的副本,若读到剩余两个副本 为(v2 v2)则v2 是最新的已提交的副本;若读到剩余的两个副本为(v2 v1)或(v1 v1)则v1 是最新成功提交的版本;若读取后续两个副本有任一超时或失败,则没法判断哪一个版本是最新的成功提交的版本。
能够看出,在单纯使用Quorum 机制时,若要肯定最新的成功提交的版本,最多须要读取R+ (W-R-1)=N 个副本,当出现任一副本异常时,读最新的成功提交的版本这一功能都有可能不可用。
实际工程中,应该尽可能经过其余技术手段,回避经过Quorum 机制读取最新的成功提交的版本。例如,当quorum 机制与primary-secondary 控制协议结合使用时,能够经过读取primary 的方式读取到最新的已提交的数据。
基于Quorum 机制选择primary副本
读取数据时依照一致性要求的不一样能够有不一样的作法:若是须要强一致性的马上读取到最新的成功提交的数据,则能够简单的只读取primary 副本上的数据便可,也能够经过上节的方式读取;
若是须要会话一致性,则能够根据以前已经读到的数据版本号在各个副本上进行选择性读取;若是只须要弱一致性,则能够选择任意副本读取。
在primary-secondary 协议中,当primary 异常时,须要选择出一个新的primary,以后secondary 副本与primary 同步数据。
一般状况下,选择新的primary 的工做是由某一中心节点完成的,在引入 quorum 机制后,经常使用的primary 选择方式与读取数据的方式相似,即中心节点读取R 个副本,选择 R 个副本中版本号最高的副本做为新的primary。新primary 与至少W 个副本完成数据同步后做为新的primary 提供读写服务。
首先,R 个副本中版本号最高的副本必定蕴含了最新的成功提交的数据。再者,虽然不能肯定最高版本号的数是一个成功提交的数据,但新的primary 在随后与secondary 同 步数据,使得该版本的副本个数达到W,从而使得该版本的数据成为成功提交的数据。
例:在N=5,W=3,R=3 的系统中,某时刻副本最大版本号为(v2 v2 v1 v1 v1),此时v1 是系统的最新的成功提交的数据,v2 是一个处于中间状态的未成功提交的数据。假设此刻原primary 副本异常,中心节点进行primary 切换工做。这类“中间态”数据究竟做为“脏数据”被删除,仍是做为新的数据被同步后成为生效的数据,彻底取决于这个数据可否参与新primary 的选举。下面分别分析这两种状况。
第1、如图 2-12,若中心节点与其中3 个副本通讯成功,读取到的版本号为(v1 v1 v1),则任 选一个副本做为primary,新primary 以v1 做为最新的成功提交的版本并与其余副本同步,当与第一、第2 个副本同步数据时,因为第一、第2 个副本版本号大于primary,属于脏数据,能够按照2.2.2.4 节中介绍的处理脏数据的方式解决。
实践中,新primary 也有可能与后两个副本完成同步后就提供数据服务,随后自身版本号也更新到v2,若是系统不能保证以后的v2 与以前的v2 彻底同样,则新 primary 在与第一、2 个副本同步数据时不但要比较数据版本号还须要比较更新操做的具体内容是否同样。
第2、若中心节点与其余3 个副本通讯成功,读取到的版本号为(v2 v1 v1),则选取版本号为 v2 的副本做为新的primary,以后,一旦新primary 与其余2 个副本完成数据同步,则符合v2 的副 本个数达到W 个,成为最新的成功提交的副本,新primary 能够提供正常的读写服务。
日志技术是宕机恢复的主要技术之一。日志技术最初使用在数据库系统中。严格来讲日志技术不是一种分布式系统的技术,但在分布式系统的实践中,却普遍使用了日志技术作宕机恢复,甚 至如BigTable 等系统将日志保存到一个分布式系统中进一步加强了系统容错能力。
Redo Log 与Check point
设计一个高速的单机查询系统,将数据所有存放在内存中以实现高速的数据查询,每次更新操做更新一小部分数据(例如 key-value 中的某一个key)。如今问题为利用日志技术实现该内存查询系统的宕机恢复。与数据库的事务不一样的是,这个问题模型中的每一个成功的更新操做都会生效。这也等效为数据库的每一个事务只有一个更新操做,且每次更新操做均可以也必须当即提交(Auto commit)。
Redo Log
-1.将更新操做的结果(例如Set K1=1,则记录K1=1)以追加写(append)的方式写入磁盘的 日志文件
2.按更新操做修改内存中的数据
3.返回更新成功
从Redo Log 的流程能够看出,Redo 写入日志的是更新操做完成后的结果(虽然本文不讨论Undo Log,这点是与Undo Log 的区别之一),且因为是顺序追加写日志文件,在磁盘等对顺序写有力的 存储设备上效率较高。
用Redo Log 进行宕机恢复很是简单,只须要“回放”日志便可。
从Redo Log 的宕机恢复流程也能够看出,只有写入日志文件的更新结果才能在宕机后恢复。这也是为何在Redo Log 流程中须要先更新日志文件再更新内存中的数据的缘由。
假如先更新内存中的数据,那么用户马上就能读到更新后的数据,一旦在完成内存修改与写入日志之间发生宕机,那么最后一次更新操做没法恢复,但以前用户可能已经读取到了更新后的数据,从而引发不一致的问题。
在简化的模型下,check point 技术的过程即将内存中的数据以某种易于从新加载的数据组织方式完整的dump 到磁盘,从而减小宕机恢复时须要回放的日志数据。
流程:check point
流程:基于check point 的宕机恢复流程
1.将dump 到磁盘的数据加载到内存。
2.从后向前扫描日志文件,寻找最后一个“End Check Point”日志。
3.从最后一个“End Check Point”日志向前找到最近的一个“Begin Check Point”日志,并回 放该日志以后的全部更新操做日志。
若数据维护在磁盘中,某批更新由若干个更新操做组成,这些更新操做须要原子生效,即要么同时生效,要么都不生效。
0/1 目录技术中有两个目录结构,称为目录0(Directory 0)和目录1(Directory 1)。另有一个结构称为主记录(Master record)记录当前正在使用的目录称为活动目录。主记录中要么记录使用目录0,要么记录使用目录1。目录0 或目录1 中记录了各个数据的在日志文件中的位置。0/1 目录的数据更新过程始终在非活动目录上进行,只是在数据生效前,将主记录中的0、1 值反转,从而切换主记录。
流程:0/1 目录数据更新流程
1.将活动目录完整拷贝到非活动目录。
2.对于每一个更新操做,新建一个日志项纪录操做后的值,并在非活动目录中将相应数据的位置修改成新建的日志项的位置。
3.原子性修改主记录:反转主记录中的值,使得非活动目录生效。
0/1 目录的更新流程很是简单,经过0、1 目录的主记录切换使得一批修改的生效是原子的。0/1 目录将批量事务操做的原子性经过目录手段归结到主记录的原子切换。
因为多条记录的原子修改通常较难实现而单条记录的原子修改每每能够实现,从而下降了问题实现的难度。
在工程中0/1 目录的思想运用很是普遍,其形式也不局限在上述流程中,能够是内存中的两个数据结构来回切换,也能够是磁盘上的两个文件目录来回生效切换。
两阶段提交协议是一种经典的强一致性中心化副本控制协议。虽然在工程中该协议有较多的问题,但研究该协议能很好的理解分布式系统的几个典型问题。
流程描述
两阶段提交协议是一种典型的“中心化副本控制”协议。在该协议中,参与的节点分为两类:一个中心化协调者节点(coordinator)和N 个参与者节点(participant)。每一个参与者节点即上文背景介绍中的管理数据库副本的节点。
两阶段提交的思路比较简单,在第一阶段,协调者询问全部的参与者是否能够提交事务(请参与者投票),全部参与者向协调者投票。
在第二阶段,协调者根据全部参与者的投票结果作出是否事务能够全局提交的决定,并通知全部的参与者执行该决定。在一个两阶段提交流程中,参与者不能改变本身的投票结果。
两阶段提交协议的能够全局提交的前提是全部的参与者都赞成提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。
流程:两阶段提交协调者流程
1.写本地日志“begin_commit”,并进入WAIT 状态;
2.向全部参与者发送“prepare 消息”;
3.等待并接收参与者发送的对“prepare 消息”的响应;3.1 若收到任何一个参与者发送的“vote-abort 消息”;3.1.1 写本地“global-abort”日志,进入ABORT;3.1.2 向全部的参与者发送“global-abort 消息”;3.1.3 进入ABORT 状态;3.2 若收到全部参与者发送的“vote-commit”消息;3.2.1 写本地“global-commit”日志,进入COMMIT 状态;3.1.2 向全部的参与者发送“global-commit 消息”;
4.等待并接收参与者发送的对“global-abort 消息”或“global-commit 消息”的确认响应消息,一旦收到全部参与者的确认消息,写本地“end_transaction” 日志流程结束。
流程:两阶段提交协调者流程
1.写本地日志“init”记录,进入INIT 状态
2.等待并接受协调者发送的“prepare 消息”,收到后 2.1 若参与者能够提交本次事务 2.1.1 写本地日志“ready”,进入READY 状态 2.1.2 向协调者发送“vote-commit”消息 2.1.4 等待协调者的消息2.1.4.1 若收到协调者的“global-abort”消息2.1.4.1.1 写本地日志“abort”,进入ABORT 状态2.1.4.1.2 向协调者发送对“global-abort”的确认消息 2.1.4.2 若收到协调者的“global-commit”消息2.1.4.1.1 写本地日志“commit”,进入COMMIT 状态 2.1.4.1.2 向协调者发送对“global-commit”的确认消息 2.2 若参与者没法提交本次事务 2.2.1 写本地日志“abort”,进入ABORT 状态 2.2.2 向协调者发送“vote-abort”消息 2.2.3 流程对该参与者结束 2.2.4 若后续收到协调者的“global-abort”消息能够响应
3.即便流程结束,但任什么时候候收到协调者发送的“global-abort”消息或“global-commit”消息也都要发送一个对应的确认消息。
异常处理
宕机恢复
1.协调者宕机恢复 协调者宕机恢复后,首先经过日志查找到宕机前的状态。若是日志中最后是“begin_commit”记录,说明宕机前协调者处于WAIT 状态,协调者可能已经发送过“prepare 消息”也可能还没发送,但协调者必定尚未发送过“global-commit 消息”或“global-abort 消息”,即事务的全局状态尚未肯定。此时,协调者能够从新发送“prepare 消息” 继续两阶段提交流程,即便参与者已经发送过对“prepare 消息”的响应,也不过是再次重传以前的响应而不会影响协议的一致性。若是日志中最后是“global-commit”或“global-abort”记录,说明宕机前协调者处于COMMIT 或ABORT 状态。此时协调者只需从新向全部的参与者发送“global-commit 消息”或“global-abort 消息”就能够继续两阶段提交流程。
2.参与者宕机恢复参与者宕机恢复后,首先经过日志查找宕机前的状态。若是日志中最后是“init”记录,说明参与者处于INIT 状态,尚未对本次事务作出投票选择,参与者能够继续流程等待协调者发送的“prepare 消息”。若是日志中最后是“ready”记录,说明参与者处于REDAY 状态,此时说明参与者已经就本次 事务作出了投票选择,但宕机前参与者是否已经向协调者发送“vote-commit”消息并不可知。因此此时参与者能够向协调者重发“vote-commit”,并继续协议流程。若是日志中最后是“commit”或“abort”记录,说明参与者已经收到过协调者的“global-commit 消息”(处于COMMIT 状态)或者“global-abort 消息”(处于ABORT 状态)。至因而否向协调者发 送过对“global-commit”或“global-abort”的确认消息则未知。但即便没有发送过确认消息,因为协调者会不断重发“global-commit”或“global-abort”,只需在收到这些消息时发送确认消息既可,不影响协议的全局一致性。
协议分析
两阶段提交协议在工程实践中真正使用的较少,主要缘由有如下几点:
1.两阶段提交协议的容错能力较差。从上文的分析能够看出,两阶段提交协议在某些状况下存在流程没法执行下去的状况,且也没法判断流程状态。在工程中好的分布式协议每每老是能够在即便发生异常的状况下也能执行下去。例如,回忆Lease 机制(2.3 ),一旦lease 发出,不管出现任何异常,Lease 服务器节点老是能够经过时间断定出Lease 是否有效,也能够用等待Lease 超时的方法收回Lease 权限,整个Lease 协议的流程不存在任何流程被阻塞而没法执行下去的状况。与Lease 机制的简单有效相比,两阶段提交的协议显得较为复杂且容错能力差。
2.两阶段提交协议的性能较差。一次成功的两阶段提交协议流程中,协调者与每一个参与者 之间至少须要两轮交互4 个消息“prepare”、“vote-commit”、“global-commit”、“确认global-commit”。过多的交互次数会下降性能。另外一方面,协调者须要等待全部的参与者的投票结果,一旦存在较慢的参与者,会影响全局流程执行速度。
虽然存在一些改进的两阶段提交协议能够提升容错能力和性能,然而这类协议依旧是在工程中使用较少的一类协议,其理论价值大于实践意义。
MVCC(Multi-version Cocurrent Control,多版本并发控制)技术。MVCC 技术最初也是在数据库系统中被提出,但这种思想并不局限于单机的分布式系统,在分布式系统中一样有效。
MVCC 即多个不一样版本的数据实现并发控制的技术,其基本思想是为每次事务生成 一个新版本的数据,在读数据时选择不一样版本的数据便可以实现对事务结果的完整性读取。在使用MVCC 时,每一个事务都是基于一个已生效的基础版本进行更新,事务能够并行进行,从而能够产生一种图状结构。
基础数据的版本为1,同时产生了两个事务:事务A 与事务B。这两个事务都各自对数据进行了一些本地修改(这些修改只有事务本身可见,不影响真正的数据),以后事务A 首先提交,生成数据版本2;基于数据版本2,又发起了事务C,事务C 继续提交,生成了数据版 本3;最后事务B 提交,此时事务B 的结果须要与事务C 的结果合并,若是数据没有冲突,即事务 B 没有修改事务A 与事务C 修改过的变量,那么事务B 能够提交,不然事务B 提交失败。
MVCC 的流程过程很是相似于SVN 等版本控制系统的流程,或者说SVN 等版本控制系统就是 使用的MVCC 思想。事务在基于基础数据版本作本地修改时,为了避免影响真正的数据,一般有两种作法,一是将基础数据版本中的数据彻底拷贝出来再修改,SVN 即便用了这种方法,SVN check out 便是拷贝的过程;二是每一个事务中只记录更新操做,而不记录完整的数据,读取数据时再将更新操做应用到用基础版本的数据从而计算出结果,这个过程也相似SVN 的增量提交。
Paxos 协议是少数在工程实践中证明的强一致性、高可用的去中心化分布式协议。Paxos 协议的流程较为复杂,但其基本思想却不难理解,相似于人类社会的投票过程。Paxos 协议中,有一组彻底对等的参与节点(称为accpetor),这组节点各自就某一事件作出决议,若是某个决议得到了超过半数节点的赞成则生效。Paxos 协议中只要有超过一半的节点正常,就能够工做,能很好对抗宕机、网络分化等异常状况。
角色
Proposer:提案者。Proposer 能够有多个,Proposer 提出议案(value)。所谓value,在工程中能够是任何操做,例如“修改某个变量的值为某个值”、“设置当前primary 为某个节点”等等。Paxos 协议中统一将这些操做抽象为value。不一样的Proposer 能够提出不一样的甚至矛盾的value,例如某个Proposer 提议“将变量X 设置为1”,另外一个Proposer 提议“将变量X 设置为2”,但对同一轮Paxos 过程,最多只有一个value 被批准。Acceptor:批准者。Acceptor 有N 个,Proposer 提出的value 必须得到超过半数(N/2+1)的Acceptor 批准后才能经过。Acceptor 之间彻底对等独立。Learner:学习者。Learner 学习被批准的value。所谓学习就是经过读取各个Proposer 对value 的选择结果,若是某个value 被超过半数Proposer 经过,则Learner 学习到了这个value。回忆(2.4 ) 不难理解,这里相似Quorum 机制,某个value 须要得到W=N/2 + 1 的Acceptor 批准,从而学习者须要至少读取N/2+1 个Accpetor,至多读取N 个Acceptor 的结果后,能学习到一个经过的value。上述三类角色只是逻辑上的划分,实践中一个节点能够同时充当这三类角色。
流程
Paxos 协议一轮一轮的进行,每轮都有一个编号。每轮Paxos 协议可能会批准一个value,也可 能没法批准一个value。若是某一轮Paxos 协议批准了某个value,则之后各轮Paxos 只能批准这个 value。上述各轮协议流程组成了一个Paxos 协议实例,即一次Paxos 协议实例只能批准一个value,这也是Paxos 协议强一致性的重要体现。每轮Paxos 协议分为阶段,准备阶段和批准阶段,在这两个阶段Proposer 和Acceptor 有各自的处理流程。
流程:Proposer 的流程 (准备阶段)
1.向全部的Acceptor 发送消息“Prepare(b)”;这里b 是Paxos 的轮数,每轮递增
2.若是收到任何一个Acceptor 发送的消息“Reject(B)”,则对于这个Proposer 而言本轮Paxos 失败,将轮数b 设置为B+1 后从新步骤1;(批准阶段,根据收到的Acceptor 的消息做出不一样选择)
3.若是接收到的Acceptor 的“Promise(b, v_i)”消息达到N/2+1 个(N 为Acceptor 总数,除法取整, 下同);v_i 表示Acceptor 最近一次在i 轮批准过value v。3.1 若是收到的“Promise(b, v)”消息中,v 都为空,Proposer 选择一个value v,向全部Acceptor 广播Accept(b, v);3.2 不然,在全部收到的“Promise(b, v_i)”消息中,选择i 最大的value v,向全部Acceptor 广播消息Accept(b,v);
4.若是收到Nack(B),将轮数b 设置为B+1 后从新步骤1;
流程:Accpetor 流程 (准备阶段)
1.接受某个Propeser 的消息Prepare(b)。参数B 是该Acceptor 收到的最大Paxos 轮数编号;V 是Acceptor 批准的value,能够为空 1.1 若是b>B,回复Promise(b, V_B),设置B=b; 表示保证再也不接受编号小于b 的提案。1.2 不然,回复Reject(B) (批准阶段)
2.接收Accept(b, v), 2.1 若是b < B, 回复Nack(B),暗示proposer 有一个更大编号的提案被这个Acceptor 接收了 2.2 不然设置V=v。表示这个Acceptor 批准的Value 是v。广播Accepted 消息。
例子
基本例子里有5 个Acceptor,1 个Proposer,不存在任何网络、宕机异常。咱们着重考察各个Accpetor 上变量B 和变量V 的变化,及Proposer 上变量b 的变化。
2.Proposer 向全部Accpetor 发送“Prepare(1)”,全部Acceptor 正确处理,并回复Promise(1, NULL
3.Proposer 收到5 个Promise(1, NULL),知足多余半数的Promise 的value 为空,此时发送 Accept(1, v1),其中v1 是Proposer 选择的Value。
4.此时,v1 被超过半数的Acceptor 批准,v1 便是本次Paxos 协议实例批准的Value。若是Learner 学习value,学到的只能是v1
在同一个Paxos 实例中,批准的Value 是没法改变的,即便后续Proposer 以更高的序号发起Paxos 协议也没法改变value。Paxos 协议的核心就在于“批准的value 没法改变”,这也是整个协议正确性的基础。
Paxos 协议是被人为设计出来,其设计过程也是协议的推导过程。Paxos 协议利用了Quorom 机 制,选择的W=R=N/2+1。
简单而言,协议就是Proposer 更新Acceptor 的过程,一旦某个Acceptor 成功更新了超过半数的Acceptor,则更新成功。Learner 按Quorum 去读取Acceptor,一旦某个value 在超过半数的Proposer 上被成功读取,则说明这是一个被批准的value。协议经过引入轮次,使得高轮次的提议抢占低轮次的提议来避免死锁。协议设计关键点是如何知足“在一次Paxos 算法实例过程当中只批准一个Value”这一约束条件。
CAP 理论的定义很简单,CAP 三个字母分别表明了分布式系统中三个相互矛盾的属性:
1.Consistency (一致性):CAP 理论中的副本一致性特指强一致性(1.3.4 );
2.Availiablity(可用性):指系统在出现异常时已经能够提供服务;
3.Tolerance to the partition of network (分区容忍):指系统能够对网络分区(1.1.4.2 )这种异常情 况进行容错处理;
CAP 理论指出:没法设计一种分布式协议,使得同时彻底具有CAP 三个属性,即1)该种协议下的副本始终是强一致性,2)服务始终是可用的,3)协议能够容忍任何网络分区异常;分布式系统协议只能在CAP 这三者间全部折中。
热力学第二定律说明了永动机是不可能存在的,不要去妄图设计永动机。与之相似,CAP 理论的意义就在于明确提出了不要去妄图设计一种对CAP 三大属性都彻底拥有的完美系统,由于这种系统在理论上就已经被证实不存在。
Lease 机制: Lease 机制牺牲了部分异常状况下的A,从而得到了彻底的C 与很好的P。
Quorum 机制: Quorum 机制,在CAP 三大因素中都各作了折中,有必定的C,有较好 的A,也有较好的P,是一种较为平衡的分布式协议。
两阶段提交协议: 两阶段提交系统具备彻底的C,很糟糕的A,很糟糕的P。
Paxos 协议:一样是强一致性协议,Paxos 在CAP 三方面较之两阶段提交协议要优秀得多。Paxos 协议具备 彻底的C,较好的A,较好的P。Paxos 的A 与P 的属性与Quorum 机制相似,由于Paxos 的协议本 身就具备Quorum 机制的因素。