分布式文件系统之一致性复制协议

阿凡达2018-07-04 14:01

分布式文件系统首要的三个要素是:

1.一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。
2.高可用(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(可用性不仅包括读,还有写)
3.分区容忍性(P):集群中的某些节点在无法联系后,集群整体是否还能继续进行服务。

      其中一致性和高可用是一对不太相容的特性。强一致性往往会导致可用性变差,因为要保证所有副本写入成功并返回才能响应读操作,吞吐量也会变差。而可用性高就需要某种程度上牺牲一致性,即即使某些副本上没有完全同步写入成功,还是可以响应读写操作。当然也不能完全牺牲一致性,完全牺牲一致性就会导致数据混乱,那就失去了分布式系统的意义。有些系统中并不要求强一致性,而是只要系统能达到最终一致性即可,考虑到客户体验,这个最终一致的时间窗口,要尽可能的对用户透明,也就是需要保障“用户感知到的一致性”。通常是通过数据的多份异步复制来实现系统的高可用和数据的最终一致性的,“用户感知到的一致性”的时间窗口则取决于数据复制到一致状态的时间。
     一致性协议大概分为以下三类:
    1.强一致性:多进程并发读写访问时,要求更新过的数据能被后续的访问都能看到。
    2.弱一致性:如果能容忍后续的部分或者全部访问不到。
    3.最终一致性:如果经过一段时间后要求能访问到更新后的数据,就是最终一致性。
作为分布式存储系统,往往都是需要强一致性。当然弱一致性和最终一致性也有其他的场景适用,例如博客等允许有一定延时但对可用性要求较高的系统。 本文重点讨论分布式存储系统常用的几种一致性复制协议,均属于强一致性范围内的。其他两种不展开讨论。
强一致性模型中几种业界常用的协议有如下几个:
1.quorum复制协议
2.主从链式复制协议
3.CRAQ协议
4.PacificA复制协议
其中NEFS系统就使用的是PacificA复制协议,经性能对比,它的吞吐量、可扩展性、一致性综合来看是比较好的。
下面对几个协议的原理进行介绍:
1.quorum复制协议原理:
quorum复制协议原理的几个概念:
N:同一份数据的Replica的份数
W:是更新一个数据对象的时候需要确保成功更新的份数
R: 读取一个数据需要读取的Replica的份数
假设N是副本数, 写Quorum W是需要写操作成功之前必须更新的副本数目 , 写Quorum R是读操作返回之前必须读取的副本数目。 当W + R > N时, 读写操作必然有交集, 读操作必能读到最新数据, 所以Quorum复制能做到强一致。

?以常见的N=3、W=2、R=2为例:
?N=3,表示,任何一个对象都必须有三个副本(Replica),W=2表示,对数据的修改操作(Write)只需要在3个Replica中的2个上面完成就返回,R=2表示,从三个对象中要读取到2个数据对象,才能返回。
 
?在分布式系统中,数据的单点是不允许存在的。即线上正常存在的Replica数量是1的情况是非常危险的,因为一旦这个Replica再次错误,就 可能发生数据的永久性错误。假如我们把N设置成为2,那么,只要有一个存储节点发生损坏,就会有单点的存在。所以N必须大于2。N约高,系统的维护和整体 成本就越高。工业界通常把N设置为3。
当W是2、R是2的时候,W+R>N,这种情况对于客户端就是强一致性的。通常配置:W=Q, R=Q ,Q=N/2+1

Quorum复制的好处灵活选择W、R, 可用性比较好, 响应时间比较低(不必等待慢节点返回结果), 缺点是维护数据历史版本代价较高,
吞吐率也不高, 常见的应用场景是元数据存储。
2.主从链式复制协议
       副本按照一定顺序关系组织成复制链, 写操作必须发送到主副本, 串行化之后依次传播到其他副本, 读操发往最后一个副本。 原始的链式复制虽然能保证强一致,但是读取的吞吐率较差。
      如图所示,所有的写操作由头结点处理,读操作/写操作的确认由尾结点处理。
头结点包含所有的写操作,从头结点到尾结点所包含的写操作越来越少(所有的操作需要从上一个节点传递下来),对写操作的确认在尾节点,读操作也在尾节点进行。
节点上的操作向下一个节点同步是FIFO的,因此后续节点上的数据记录肯定是前面节点的前缀。
比如:
HEAD节点: (a=1) (b=2) (c=3) (d=4)
TAIL节点: (a=1) (b=2)
TAIL节点上的数据记录是HEAD节点、MIDDLE节点的前缀,MIDDLE节点上的记录是HEAD节点记录的前缀。
HEAD: (a=1) (b=2) (c=3) (d=4)
 MIDDLE: (a=1) (b=2) (c=3)
TAIL : (a=1) (b=2)
头结点拥有四个写操作,其中a=1,b=2已经达到尾节点,由尾节点向客户端返回成功。
c=3,d=4这两条记录尾节点还未返回成功。
这时如果客户端的读发生(落在尾节点),因此只能读到(a=1,b=2)这两条记录;(c=3,d=4)这两条记录现在读不到。
 
3.CRAQ协议

        对主从链式复制的优化:通过维护一个脏标记CRAQ允许读取任意副本, 从而提高了读吞吐率。

4.PacificA复制协议
        PacificA是微软提出的一种保证强一致的主从复制方法, 适用于基于日志的存储系统, 分布式日志系统kafka就是采用这种做法。 PacificA复制分为三个阶段。 第一阶段prepare, 主节点确定更新顺序, 发送数据到所有从节点, 从节点写入日志并返回响应给主节点。 主节点收到所有从节点的响应之后进入第二阶段“主commit”, 主节点在本地commit该数据, 紧接着返回客户端, 此后客户端能读到该数据。 第三阶段从commit, 主节点本地commit后,异步(或者通过后续prepare消息捎带)commit所有从节点。 该协议保证更新串行性, 确保数据一但commit就能被读到。

 该协议中所有的请求插入到prepare list中,

在prepare list中维护一个commit点,所有的请求都有一个序列号,

我们将请求顺序插入到prepare list中,只有当编号为sn-1的请求插入到链表中后,

编号为sn的请求才能插入,如图所示prepare list中commit点之前的为commit list。

CheckPoint点之前的数据已经持久化

Commited点之前的数据对客户端可见

Commited ~ prepared之间的数据是正在做复制的数据对客户端不可见

(这部分数据可能提交,也有可能不提交)

主从复制的流程图如下所示:

Commit Invariant: p表示primary replica,q任意secondary replica, 根据复制协议必然满足以下约束:

 一个复制过程的实例如下:

 算法分析来看,PacificA算法相对于之前的几个算法来说,相对缺点较少,不需要维护历史版本,也解决了链式复制导致的吞吐量较差的问题。

经过实际评测,PacificA算法在吞吐量,效率,可扩展性等方面都比较好。

相关阅读:分布式文件系统典型异常场景剖析及模拟(一)

分布式文件系统典型异常场景剖析及模拟(二)

本文来自网易实践者社区,经作者崔晓晴授权发布。