當前位置:
首頁 > 知識 > 分布系统之中心化复制集

分布系统之中心化复制集


中心化副本控制协议

所谓的中心化,就是对于副本集的更新操作有一个中心节点来协调管理,将分布式的并发操作转化为单点的并发操作,从而保证副本集内各节点的一致性。其优点在于逻辑简单,将复杂的问题(分布式并发)转换成一个有成熟解决方案的问题(单点并发)。但缺点在于,副本集的可用性依赖于中心节点,如果中心节点故障,即使有中心节点自动切换机制,也会出现数10秒的不可用。

分布系统之中心化复制集

大多数的分布式存储都会采用中心化副本控制协议,比如GFS,TFS,MongoDB

而去中心化则是说副本集中没有中心节点,所有节点的地位是平等的,大家都可以接受更新请求,相互通过协商达成数据的一致。去中心化副本控制协议的最大好处在于可用性比较强,只要有大多数节点存活就能提供服务。但缺点时协议流程复杂,尤其是需要强一致性保证的时候。

在业界中,Dynamo,cassandra就是基于去中心化协议,虽然 Dynamo 尝试通过引入 Quorum 机制和 vector clock 机制解决读取数据的一致性问题,但其一致性模型依旧是一个较大的问题。

本文主要对中心化副本控制协议进行详细介绍。

中心化副本控制协议在分布式存储系统中使用非常规范,但各家实现又有不同。这里主要集合分布式文件系统与分布式数据库来做对比分析

对于中心化副本控制协议,提出了以下疑问:

第一个问题:复制集之间数据的同步是同步模式还是异步模式。

在中心化副本控制协议中,主节点(primary)提供写入操作,数据会同步到其他节点。注意,上面语句中第一个同步是指复制集中节点间数据趋于一致的过程。

所谓同步(Synchronous replication),就是说对于客户端请求,系统阻塞到复制集中所有节点都更新完成,才能向客户端返回,即write all。而异步(Asynchronous replication)模式,只要一个或者部分节点更新则算写入操作成功,通常是write one。

分布系统之中心化复制集

上图(来源于Distributed systems for fun and profit,下同)即为同步模式,客户端的请求被发送到s1这个副本集,s1将请求转发给s2、s3,等s2、s3都操作完成之后再向客户端返回结果。

在同步模式下,系统的可靠性非常好,只要有一个节点正常,就能保证数据不丢失。但是系统的更新可用性非常差,只要有一个节点异常,就无法完成更新;而且,响应延迟比较大,取决于副本集中网络延时最大、处理速度最慢的节点。

分布系统之中心化复制集

上图则是异步模式,客户端的写请求只要在一个节点上完成就立即向客户端返回结果。在上图中,数据被写入到s1即认为写入成功,向客户端返回,系统在后台由s1向s2、s3节点同步数据。

异步模式下,系统的吞吐量会比较好,但是存在数据丢失的风险,比如上图中,如果在数据同步到s2 s3之前s1挂掉,那么刚才客户端的更新就丢失了,关键在于客户端认为已经写入成功了。另外,异步模式下,客户端在写入成功之后,立刻从系统读取数据,有可能读不到最新的数据,比如上图中,客户端写入s1之后立刻从s2 读取。

在数据同步的时候选择同步模式还是异步模式呢,这个取决于系统对一致性、可用性、响应延迟的要求。

比如在分布式文件系统GFS中,需要保证复制集内副本的强一致性,而单次读写的响应延迟并没有那么重要,因此选择了同步模式,即primary需要等到所有的secondary都写入成功才会向客户端返回。

而在分布式数据库MongoDB中,决定权交给了用户,用户可以决定使用同步模式还是异步模式。如果w:1.那么只会写入到primary节点就立即返回,系统会在后台向secondary节点同步数据,即为异步模式。如果w:N(N为复制集节点数目),那么primary节点需要等到所有secondary都更新到最新的数据之后(或者等待超时)才向客户端返回,也就是同步模式。即使在去中心化副本控制协议,如cassandra,也提供给用户自行设定一致性等级。

前面已经提到了同步模式、异步模式各自的优劣,这里以MongoDB为例具体讨论,看看同步、异步模式对系统一致性、可用性的影响。

在异步模式(w: 1)下,系统的响应延迟很低,可用性非常好,但存在两个问题。第一:同一个客户端在得到成功写入的返回之后立即从secondary节点读取,有可能读不到最新的数据;第二:在主从切换的时候(后面会详细讲解这一过程),可能发生rollback,简单来说,数据只持久化到了primary,secondary节点还未更新到最新的数据,此时如果primary故障,系统会选举出新的primary,即使旧的primary恢复正常后以secondary身份重新加入复制集,新的primary不会承认其数据,这就导致了更新丢失的问题。

同步模式下(w:N或者w:Majority),需要等待所有节点都写入成功,响应延迟会比较高,在数据库应用中一般很难接受,之前基于《通过一步步创建sharded cluster来认识MongoDB》中的复制集(一个primary、一个secondary、一个arbiter)做过实验,如果将secondary shutdown(db.shutdownServer),然后用writeConcern: {w: "majority”, wtimeout: 10}写入数据,客户端会阻塞到超时,然后给出超时信息。不过,w:majority保证了写入的数据不会丢失,即不会出现rollback的问题。

第二个问题:数据的流向

即数据是如何从Primary节点到secondary节点的。

首先是比较有意思的GFS,GFS写入流程如下:

分布系统之中心化复制集

GFS的写入将控制流与数据流分开,客户端会把数据流链式推送到各个节点,推送的过程并不关心谁是primary、谁是secondary。需要注意的是,各节点(GFS中称之为chunkserver)只是缓存数据,等到Primary向secondary发送持久换指令(step5)的时候再回真正持久化写入。

更一般的,数据的流向有两种,链式与主从模式。

链式就是指从一个节点推送到最近的节点,比如GFS,“最近” 可以用IP地址或者节点间心跳TTL来衡量,如图所示(图片来源于清华阿里-大数据课程的PPT):

分布系统之中心化复制集

不难看出,写入过程中每个节点的带宽利用都比较均衡,可以充分利用网络资源,也不会有单点压力;但是需要经过多个节点,写入延迟会比较大。

而主从模式则是指数据同时从primary节点到secondary节点,如图所示(来源)

分布系统之中心化复制集

MongoDB就是采用了主从模式,Secondary会从Primary拉取OPLOG并应用到本地。显然,在这种模式下Primary节点的带宽压力比较大,但是写入延迟会小一些。

第三个问题:部分节点写入失败了怎么办

不管是同步模式还是异步模式,也不管是链式推送还是主从模式推送,复制集中数据的写入都是1PC(1 phase commit)。即数据的更新只有一个commit阶段,而没有prepare阶段,如果某些节点发生故障,那么提交在故障节点上会失败,甚至是提交了部分、不完整的数据。

复制集中多个节点的更新本质上来说应该是分布式事务问题,理论上应该保证原子行:要么都更新成功,要么都不更新,而不会出现部分节点更新成功的情况。但经典解决方案如两阶段提交代价太大,因此分布式存储中的复制集更新大多采用best effort 1pc,只不过不同的系统对更新失败的处理有所区别。

比如MongoDB,以第一个问题中提到的例子,writeconcern为w: majority,由于其中一个secondary挂掉,写入操作是不可能成功的。因此,在超时时间到达之后,会向客户端返回出错信息。但是在这个时候直接连接到rs的primary节点,数据是持久化到了primary节点,不会被回滚。

另外,对于分布式图片存储haystack,如果更新失败,会重试流程,直到成功或超时,重试的话所有节点都会重试。那么可能出现两个问题,某个节点上数据部分写入(写入部分数据就崩溃了);由于重试是对复制集中所有节点重试,因此某个节点上同一份数据可能写入了多份。对于第一个问题,由于有checksum,因此不怕部分写入失败;第二个问题,由于有offset和元数据,重复写入也不是问题。haystack(以及GFS)通过这种巧妙的方式解决了分布式更新问题。

主从节点数据读取

复制集中,不同的系统在数据读取方面有两个问题。第一:secondary节点是否提供读服务;第二,如果可以从Secondary读取,那么这个接口是否开放给用户

第一个问题,如果secondary节点提供数据读取服务,那么是否会读取到过期的数据(即不是最新成功写入的数据) ?比如在异步写入的时候,客户端得到成功写入的返回之后,立即去secondary上读取,那么有可能读到过时的数据,这对于强一致性的情况是不能允许的。我们知道,元数据的管理一般也是复制集,而元数据需要保证强一致性,因此,元数据的写入一般都是同步的。比如GFS中,master由一个active(也就是primary节点)、多个standby(也就是secondary节点)组成,在元数据写入到active的时候,要保证本地和远程机器都写入成功才能返回;而且只有active提供读取服务。

第二个问题,如果复制集中的节点都能提供读取服务,那么接口是否提供给最终用户呢?在haystack中,多个在不同机器上的物理卷组成一个逻辑卷,一个逻辑卷就是一个复制集。当读取请求到达的时候,是由haystack的元数据服务器(directory)根据负载均衡的原则选出提供服务的物理卷,即用户是不知道读取请求是落地到哪个物理节点的。而对于mongodb,用户可以在查询语句里面指定是从Primary读取,还是从Secondary读取,或者让系统来选择(Nearest)。

读取方式与用户角度的一致性非常相关,比如在MongoDB中,不同的readrefence导致一致性、可用性的差异,具体可见《CAP理论与MongoDB一致性、可用性的一些思考》

主节点选举

在中心化副本控制协议中,这个中心(primary)是怎么选出来的呢?是上级指定还是民主选举呢?

GFS系统中,Primary节点是由master(GFS中的元数据服务器)通过lease机制选择的。简单说来,GFS给某个节点颁发Lease,该节点就成为了Primary节点,Primary节点也可以在过期之前重新申请Lease,而且Lease的颁发、申请信息都是在chunkserver与master的心跳中,因此也不会带来过多额外的开销。使用Lease机制能很好的避免在复制集中出现双主(同时有两个节点认为自己是Primary)现象。

而在Zookeeper、TFS、MongoDB中,都是通过去中心化的协议选举出Primary节点,选举出Primary节点之后,就变成了中心化的副本控制协议,当Primary出现故障之后,会重新选举过程。对于民主选举,两个因素非常重要:第一是强一致性,只能选举出一个Primary;第二个是可用性,选举过程要越快越好。

为了达到强一致性,需要使用分布式一致性协议,目前较为常见的协议有Paxos协议,该协议可以实现所有备份均可以提供对外服务,并且保证强一致性,通过理论和实践检验可以达到分布式的要求。Raft协议则是Paxos的一种特化,在这个协议的实现中,备份间需要区分主从角色,只有主节点可以提供对外服务,协议实现简单高效,能很容易的同各种分布式数据一致性同步场景相结合,是工程实现最好的选择。

在mongodb3.2中,Primary选举算法改成了raft-like算法,此举的目的也是为了缩短选举的时间,具体可见Replica Set Protocol Version。

在TFS中,meta server(元数据服务器)也是通过raft协议选举primary的,下面两个gif形象展示了primary初始选举以及当primary故障之后的重新选举(图片来源于清华阿里-大数据课程的PPT)。

分布系统之中心化复制集

上图展示了Primary选举过程

分布系统之中心化复制集

上图展示了在原来的Primary挂掉之后(也可能仅仅是失去响应),剩余的节点是如何选举出新的Primary。

为了防止出现双主的情况,在投票过程中至少要有超过半数的节点同意才能选出Primary,这也是为什么复制集中节点数目都是奇数个的原因。


中公优就业IT培训,总有你想学的:http://xue.ujiuye.com

勤工俭学计划,0元学IT!

http://www.ujiuye.com/zt/qgjx/?wt.bd=mmxtt

找工作太难?好汉,让我助你一臂之力!

http://www.ujiuye.com/zt/jyfc/?wt.bd=mmxtt

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT优就业 的精彩文章:

微服务简介——微服务从设计到部署
Consumed parameters耗用参数
掌握以下四个技巧,办公效率提高十倍

TAG:IT优就业 |

您可能感興趣

杀人犯潜逃12年 以收破烂为生 智能系统让其现形