Paxos工程实践--Google chubby设计与实现
来源:互联网 发布:vr淘宝宣传视频 编辑:程序博客网 时间:2024/06/05 17:03
Paxos算法在工程实现时,会遇到非常多的问题,工程实现中很多细节算法并不涉及,同时如何达到较好的性能和稳定性也是一个挑战。Google的分布式锁服务chubby底层就是以Paxos算法作为基础的,这给我们提供了一个很好的范例,展示了如何填补Paxos基本算法在工程实现中的空白之处。
Chubby是以5台独立的机器组成一个cell来提供一个可靠的锁服务,5台机中只要不超过两台出错都不影响服务运行。Chubby的基本架构大致分为三层:
- 最底层是 log replication,通过Paxos算法保证5台机的log完全一致,同时具备容错性
- log层之上就是Key-Value类型的数据存储层,通过下层的log来保证一致性和容错性
- 存储层之上再实现Chubby提供的锁服务和小文件存储服务
先从Log层说起。
每台机器的数据存储状态可看做一个状态机,只要给定相同的输入序列,状态机就能保证一致的变化,这就是 state machine replication。所以呢,这里的Log层目的就是实现一致的log replication。
但是Paxos算法只能从多个不同proposal value中确定一个一致的value,而这里log需要确定的是无限多个value(提供不间断服务,log无限增长),因此,每个value的确定需要一个Paxos instance。多个instance之间不相干,可以并行进行。当然每个instance也需要一个唯一的instance编号,instance编号按序分配并顺序写入log。把Paxos每个两阶段提交过程Prepare->Promise->Propose->Accept称作一个round,每个Paxos instance内又可能经过多个round才达成一致。这就是Multi-Paxos算法。
上述算法存在大量的优化空间:
- 多个Proposor的活锁问题会严重影响效率,导致每个instance可能要多个round才能达成一致。
- 在每个replica上,多个instance的Prepare->Promise阶段可以合并成一个。
先考虑第二点,如何合并多个instance的Prepare->Promise阶段。原本,多个instance之间是完全独立的,每个instance自己决定每一个round序号,保证在instance内部不重复即可,但现在为了合并Prepare->Promise阶段,多个instance公用一套序号分配,具体做法如下:
- 当某个replica通过选举获得master资格后,用新分配的编号N广播一个Prepare消息,这个Prepare消息被所有未达成一致的instance和将来还未开始的instance共用。
- 当Acceptor接收到Prepare后,现在必须对多个instance同时做出回应,这可以封装在一个数据包中,假设最多允许K个instance同时选举,那么:
- 当前至多有K个未达成一致的instance,将这些未决的instance各自最新accept的value(若没有用null代替)封装进一个数据包,作为Promise消息返回
- 同时,标记这些未决instance和所有未来instance的highestPromisedNum为N,如果N比它们原先的值大的话。这样,这些未决instance和所有未来instance都不能再accept编号小于N的Proposal。
- 然后master就可以对所有未决instance和所有未来instance分别执行Propose->Accept阶段,始终使用编号N,如果这个master保持稳定的话,就再也不需要Prepare->Promise了。但是,一旦发现acceptor返回了一个reject消息,说明另一个master启动,用更大的编号M>N发送了Prepare消息,这时自己就要分配新的编号(必须比M更大)再次进行Prepare->Promise阶段。
这里面还有一个小的可以改进的地方。如果允许并行执行多个instance,master切换之时,新的master收到的Promise消息可能包含不连续的未决instance,即出现“gap”,state machine replication执行的时候必须按顺序执行log,遇到gap就必须等待gap处的instance达成一致value才能继续执行。为了缩短卡在gap处的时间尽快执行后续log指令,在Promise阶段对gap处提交no-operation指令,最后执行log指令时碰到no-op直接跳过。
对state machine replication的读操作,如果要保证读到最新的数据,必须也为读操作建立一个Paxos instance,序列化写入log,这样对大量的读操作性能就不高。因此,我们需要一个“安全”的选举算法,保证任意时候不出现多个master,这样,就可以对非master机器禁止commit操作,然后将读操作全部集中到master上,这样就能保证读操作始终读到最新的数据。如何实现这个“安全"的选举算法,请点击这里。
实现了一致的log replication,就可以在上层实现一个一致的state machine replication,这就是前边图中的fault-tolerant DB层。DB层在内存中的数据结构这里不做讨论,这里就大致说下snapshot+replay log的实现,这是比较简单的一个问题。
在宕机重启以后,为了恢复state machine 状态,需要将已有的log重新执行一遍,但是如果log积累了很多,那么恢复的时间就非常长,因此需要定期对state machine做一个snapshot存入磁盘,然后就可以将snapshot点之前的log删去。为了避免snapshot阻塞state machine的更新操作,可以建立一个shadow state machine,平常执行log时分别在state machine和shadow上执行,在开始snapshot后,冻结shadow,但不影响原state machine执行,snapshot完成后,再让shadow追赶上最新的log。在新的snapshot完成后才能删除旧的snapshot,这样snapshot执行一半时宕机也不影响恢复。如果state machine占用空间非常大,那么这种简单的整体snapshot方式可能开销就比较大,可以使用更好的办法,这个问题放到别的文章里讨论。
replica宕机后的恢复,分为两种情况,一种是磁盘未损坏,盘上snapshot+log可以恢复到之前某个时间的状态,然后向别的replica索取宕机后缺失的部分,一种磁盘损坏用空盘代替,这时就需要从别的replica索取整个状态,但处理方法是类似的,如果缺的比较少,可能只需要传输近期的log就够了,如果宕机太久或者需要整个重建,那就要传输最近的snapshot+log。
replica宕机重启之后,为了安全起见,暂时不能立即开始参与Paxos instance,需要等待观测到K个Paxos instance成功完成之后,K是允许并发的instance数目。这样就能保证新分配的编号(比观测到的都大)不和自己以前发过的重复。前边提到的一致读操作,也要等到这个时刻到来以后才允许开始。
log是否需要实时commit进磁盘?只要任意时刻保证多数派的机器正常运行,那么宕机后未flush到磁盘的一小部分log也可以从正常的replica中获取,因此不需要实时flush log。这可以极大的提高写盘效率。
在Fault-tolerant DB层之上,就可以比较容易的构建一个分布式锁服务--Chubby,当然需要讨论的问题还有很多,如Chubby中client cache一致性,session状态恢复,keep-Alive机制等等,且听下回分解。
- Paxos工程实践--Google chubby设计与实现
- Paxos的工程实践之Chubby。
- 【分布式】Chubby与Paxos
- Chubby与Paxos
- 【分布式3】——Chubby与Paxos
- Paxos的工程实践之Hypertable。
- Google利器之Chubby
- Google——Chubby
- Google Chubby介绍
- 谈Google Chubby
- chubby中使用paxos的分析
- 分布式锁服务Chubby之paxos算法
- Google论文小结之Chubby
- paxos 算法实现和设计要点
- 【图书】前端工程化:体系设计与实践
- multi paxos在ceph monitor中的工程实现
- <从PAXOS到ZOOKEEPER分布式一致性原理与实践>读书笔记-paxos算法
- 从PAXOS到ZOOKEEPER分布式一致性原理与实践--Paxos算法
- C语言数组名a和&a小结
- Mac OS访问Windows共享文件夹
- 调用Cognos sdk接口生成报表
- 一个python 3.2下的 高级 电子邮件库 pyzmail
- dbms_stats.gather_table_stats与analyze table 的区别[转贴]
- Paxos工程实践--Google chubby设计与实现
- Halcon學習之八:圖像區域疊加與繪制
- java—如何成为高手
- Halcon學習之七:改變圖像的現實方式和大小
- NSObject控件树继承关系
- 内核编译错误: make: *** [.tmp_vmlinux1] Error 1
- Halcon學習之六:獲取Image圖像中Region區域的特征參數
- GCC编译程序时的四个阶段说明!
- Halcon學習之五:有關圖像的定義域的函數