文章目录
简介
pacificA协议算是一个分布式的架构解决方案,在正常的分布式系统中,比如hdfs,kafka,elasticsearch中,系统对整个集群的元数据的管理需求和对本身存储的业务数据的管理需求是不同的。
比如,元数据一般采用leader写入模式,而且要求具备线性化的读写,但是这部分的数据一般是量不大,一致性要求高,尽可能的提供更高的可用性,但是对于业务数据,可能需要备份的数量不同(备份的数量和可用性一般是成反比的),pacificA的存在就是为了试图优化这个问题,简化系统设计。
在满足线性化读写的分布式系统中,目前的系统设计都是由master进行写入,然后像follower进行同步,假如master不会宕机,那么是可以永远满足分布式一致性的,通常都是有问题了应该如何处理这一块儿,现在大部分系统都是进行master选举,这一块儿也引入了系统了复杂度。如果我们对业务系统设计成一个master永远不会挂掉(这里不是真的物理上不会挂掉,而是通过一些措施来保证),而且只管理业务数据的一致性系统,集群的元数据的一致性就交给另外的模块去管理,这样是不是就舒服很多了。而pacificA的设计理念就是这样的。
在一个pacificA架构中主要有两个模块
- Configuration Manager: 扮演上帝角色,主要负责集群的元数据信息的一致性维护,同时也负责replica group的管理工作
- Replica Group:这个主要是用来完成业务数据的存储工作
在这种设计模式下,pacificA没有强调Configuration Manager
,你可以使用任何一个分布式一致性协议(raft,zab,viewstamp),或者是借助zookeeper来实现,然后他主要介绍的是如何实现Replica Group
的实现,以及Configuration Manager
如何和Replica Group
交互和管理Replica Group
。
下面文章叙述的大部分参考阿里大佬王怀远的这篇文章
1. pacificA中的一些名词
- Replica Group:一个互为副本的数据集合叫做Replica Group,每个副本是一个Replica。一个Replica Group中只有一个副本是Primary,其余为Secondary。
- Configuration:一个Replica Group的Configuration描述了这个Replica Group包含哪些副本,其中Primary是谁等。
- Configuration Version:Configuration的版本号,每次Configuration发生变更时加1。
- Configuration Manager: 管理Configuration的全局组件,其保证Configuration数据的一致性。Configuration变更会由某个Replica发起,带着Version发送给Configuration Manager,Configuration Manager会检查Version是否正确,如果不正确则拒绝更改。
- Query & Update:对一个Replica Group的操作分为两种,Query和Update,Query不会改变数据,Update会更改数据。
- Serial Number(sn):代表每个Update操作执行的顺序,每次Update操作加1,为连续的数字。
- Prepared List:Update操作的准备序列。
- Committed List:Update操作的提交序列,提交序列中的操作一定不会丢失(除非全部副本挂掉)。在同一个Replica上,Committed List一定是Prepared List的前缀。
2. Replica Group 的工作模式
Replica Group
和raft协议中的leader和follower构成的一个集群一样,如果比较具体的就是ES的某个shard的primary shard和replica shard共同构成的group就是Replica Group
,接下来来看一下假如对于client的读写操作,Replica Group
是如何处理的呢。
1. 正常读写模式
1. 读,Query
Query流程比较简单,Query只能发送给Primary,Primary根据最新commit的数据,返回对应的值。由于算法要求满足Primary Invariant,所以Query总是能读到最新commit的数据。
2. 写 Update
Update流程如下:
- Primary分配一个Serial Number(简称sn)给一个UpdateRequest。
- Primary将这个UpdateRequest加入自己的Prepared List,同时向所有Secondary发送Prepare请求,要求将这个UpdateRequest加入Prepared List。
- 当所有Replica都完成了Prepare,即所有Replica的Prepared List中都包含了该Update请求时,Primary开始Commit这个请求,即将这个UpdateRequest放入Committed List中,同时Apply这个Update。需要注意的是,同一个Replica上,Committed List永远是Prepared List的前缀,所以Primary实际上是提高Committed Point,把这个Update Request包含进来。
- 返回客户端,Update操作成功。
需要注意的是,这里的第2步结束后并不会想zab当中那样立刻广播commit消息,而是像raft当中的那样,当下一次Primary向Secondary发送新的数据同步请求时,会带上Primary当前的Committed Point,此时Secondary才会提高自己的Committed Point。
这里也可以看出primary是领先secondary的。
2. primary 和secondary之间的交互
-
primary要定期的使用心跳来检测secondary是否还活着,如果secondary不再存活了,那么primary就要向
Configuration Manager
报告,进而让Configuration Manager
将这个secondary从Replica Group中剔除。 -
同样的,secondary也要检测primary是否存活,如果secondary联系不上primary,那么secondary就需要向
Configuration Manager
报告,进而从secondary中选一个做primary。 -
如何保证当一个Replica认为自己是Primary时,Configuration Manager中维护的Configuration也认为其是当前的Primary。任何时候,最多只有一个Replica认为自己是这个Replica Group的Primary呢。
- 论文给出的一种方法是通过Lease机制,这也是分布式系统中常用的一种方式。具体来说,Primary会定期获取一个Lease,获取之后认为某段时间内自己肯定是Primary,一旦超过这个时间还未获取到新的Lease就退出Primary状态。只要各个机器的CPU不出现较大的时钟漂移,那么就能够保证Lease机制的有效性。
- 论文中实现Lease机制的方式是,Primary定期向所有Secondary发送心跳来获取Lease,而不是所有节点都向某个中心化组件获取Lease。这样的好处是分散了压力,不会出现中心化组件故障而导致所有节点失去Lease的情况。
- 同时这个Lease的时长应该 >> primary对secondary的健康检查间隔时间 , 然后secondary对leader不存在的超时判断要结合健康检查和Lease的时长。这样才能避免出现了两个leader的情况。
3. 非正常模式下的逻辑处理
1. Secondary故障
当一个Secondary故障时,Primary向Configuration Manager发起Reconfiguration,将故障节点从Replica Group中删除。一旦移除这个Replica,它就不属于这个Replica Group了,所有请求都不会再发给它。
假设某个Primary和Secondary发生了网络分区,但是都可以连接Configuration Manager。这时候Primary会检测到Secondary没有响应了,Secondary也会检测到Primary没有响应。此时两者都会试图发起Reconfiguration,将对方从Replica Group中移除,这里的策略是First Win的原则,谁先到Configuration Manager中更改成功,谁就留在Replica Group里,而另外一个已经不属于Replica Group了,也就无法再更新Configuration了。但是如果一个好好工作的primary因为某个不靠谱的secondary频繁发生网络分区而频繁更换primary也是很痛苦的事儿。所以在上面也提到了,由于Primary会向Secondary请求一个Lease,在Lease有效期内Secondary不会执行Reconfiguration,而Primary的探测间隔必然是小于Lease时间的,所以我认为这种情况下总是倾向于Primary先进行Reconfiguration,将Secondary剔除。
2. Primary故障
当一个Primary故障时,Secondary会收不到Primary的心跳,如果超过Lease的时间,那么Secondary就会发起Reconfiguration,将Primary剔除,这里也是First Win的原则,哪个Secondary先成功,就会变成Primary。
当一个Secondary变成Primary后,需要先经过一个叫做Reconciliation的阶段才能提供服务。这个也就和zab中leader选出来提交一个空的log,zab中的synchronization是一样的作用,保持Replica Group
中的数据和primary对齐。原先的Primary的Committed List一定是新的Primary的Prepared List的前缀,那么我们将新的Primary的Prepared List中的内容与当前Replica Group中的其他节点对齐,相当于把该节点上未Commit的记录在所有节点上再Commit一次,那么就一定包含之前所有的Commit记录。
3. secondary增加
新加的节点需要先成为Secondary Candidate,这时候Primary就开始向其发送Prepare请求,此时这个节点还会追之前未同步过来的记录,一旦追平,就申请成为一个Secondary,然后Primary向Configuration Manager发起配置变更,将这个节点加入Replica Group。
还有一种情况是,如果一个节点曾经在Replica Group中,由于临时发生故障被移除,现在需要重新加回来。此时这个节点上的Commited List中的数据肯定是已经被Commit的了,但是Prepared List中的数据未必被Commit,所以应该将未Commit的数据移除,从Committed Point开始向Primary请求数据。
也可以参考这一篇不太成熟的翻译来加强理解