Ceph的Paxos源码注释 - Phase 1

本文详细介绍了Ceph中Paxos协议的Phase 1,包括Epoch、Proposal Number(PN)、Version的概念及作用,并讨论了持久化机制。Phase 1的目标是就PN达成一致,文章通过代码分析了该过程的关键步骤,包括初始化、Leader的collect操作、peon的响应处理等。
摘要由CSDN通过智能技术生成

欢迎关注存储老小伙的博客。

本文之前的版本全是代码和注释,没有讲解,本次做了大量调整。

上篇是Leader 选举部分。这篇主要是Ceph的Paxos协议的Phase1(Prepare),其目的是就PN达成一致。

1. 几个要点说明

1.1 Epoch

每次选举产生新的leader,也会产生新的epoch。不选举则不会修改epoch。
一个leader当选期间,发送的所有消息,都会带有这个epoch。
如果由于网络分割等现象,有新的选举发生,则根据epoch就发现leader已经变了。
注意,按照paxos论文描述,没有Leader也是可以正常运行的,只是可能降低效率。
没有leader则不需要epoch

1.2 PN (Proposal Number)

Leader当选后,会首先执行一次phase 1过程,以确定PN。 在其为leader期间,
所有的phase 2操作都共用一个PN。所以省略了大量的phase 1操作,这也是
paxos能够减小网络开销的原因。 “Paxos made simple”文中说:
“A newly chosen leader executes phase 1 for infinitely many
instances of the consensus algorithm”。
PN是必须的,无论是否有leader,都必须有PN

1.3 Version

可以理解成Paxos 的instance ID,或者raft的logID。

1.4 持久化

对比Raft,虽然ceph的复制也可以看成一个个log的追加,
但是所有信息都写在k/v中,而不是写log文件, 比如,instanceID为X的log,
在k/v存储中,其key是X,value是log内容。
其他各种需要持久化的值,都写在k/v存储中。

1.5其他需要持久化的数据结构

除了log以外,每个paxos成员,都维护以下几个需要持久化的变量。
大家可以跟raft的paper做些简单对比。

名称 含义 其他
last_pn 上次当选leader后生成的PN get_new_proposal_number()使用,下次当选后,接着生成
accepted_pn 我接受过的PN,可能是别的leader提议的PN peon根据这个值拒绝较小的PN
first_committed 本节点记录的第一个被commit的版本 更早的版本(日志),本节点没有了
last_committed 本节点记录的最后一次被commit的版本 往后的版本,未被commit,可能有一个
uncommitted_v 本节点记录的未commit的版本,如果有,只能等于last_commit+1 ceph只允许有一个未commit的版本
uncommitted_pn 未commit的版本对应的PN 与uncommitted_v,uncommitted_value在一个事务中记录
uncommitted_value 为commit的版本的内容 见上面

注意,上述三个”uncommitted”开头的值,可能压根就不存在,比如正常关机,全部都commit了。

1.6 Phase 1交互过程简介

Phase 1就是 paxos协议的Propose阶段,包括三个步骤,如下表:

步骤 Leader Peons 备注
1 collect() => Leader给quorum中各个peon发送PN以及其他附带信息
2 <=handle_collect() Peon同意或者拒绝PN。并中间可能分享已经commit的数据
3 handle_last() Quorum中peon全部同意leader的PN,才算成功

2. 代码

2.1 初始化
void Paxos::init()
{ //几个持久化的变量,加载时即从从kv读出。
  // load paxos variables from stable storage
  //上次产生的PN
  last_pn = get_store()->get(get_name(), "last_pn");
  //上次接受的pn
  accepted_pn = get_store()->get(get_name(), "accepted_pn");
  //最近或最后一个被commit的verion,实际上是paxos 的instance ID。
  last_committed = get_store()->get(get_name(), "last_committed");
  //保存的最早被commit的版本(log)。更早的log可能已经被truncate掉了
  first_committed = get_store()->get(get_name(), "first_committed");

  //paxos的 first_committed,并不是某个monitor的first_committed,各个monitor
  //对应值可能都是不一样的。
  assert(is_consistent());
}
2.2 Leader发起的collect
// PHASE 1:  collect和handle_collect基本能对应paxos的phase 1
//这是leader的当选后执行函数,用于确定新的PN。
//collect过程,相当于完成当选期间所有提议的phase 1。
//在其当选期间,会一直使用这个PN
void Paxos::collect(version_t oldpn)
{
 // we're recoverying, it seems!
  state = STATE_RECOVERING;
  assert(mon->is_leader());

  // reset the number of lasts received
  uncommitted_v = 0; //新当选,初始化
  uncommitted_pn = 0;
  uncommitted_value.clear();
  peer_first_committed.clear();
  peer_last_committed.clear();

  //ceph的实现中,只允许有一个proposal处于pending状态(跟raft相同)。
  //如果新leader当选后发现有pending的提议,那么其instanceID/version
  //只能是last_committed+1
  if (get_store()->exists(get_name(), last_committed+1)) {
    /*pending_v, pending_pn和last_committed+1是一个事务写的。
     所以一起检查 */
    version_t v = get_store()->get(get_name(), "pending_v");  
    version_t pn = get_store()->get(get_name(), "pending_pn"); 
    if (v && pn && v == last_committed + 1){
  //这个是正常分支
      uncommitted_pn = pn;
    } else {
      dout(10) << "WARNING: no pending_pn on disk, using previous accepted_pn " << accepted_pn  << " and crossing our fingers" << dendl;
      uncommitted_pn = accepted_pn;
    }
    uncommitted_v = last_committed+1;
    //找到uncommitted_v (这个key)对应的value
    get_store()->get(get_name(), last_committed+1, uncommitted_value);
    //uncommitted_v存在,要求uncommitted_value必须存在。    
    assert(uncommitted_value.length()); 
    logger->inc(l_paxos_collect_uncommitted);
  }

  //生成一个新的更大的PN,并自己先accept
  accepted_pn = get_new_proposal_number(MAX(accepted_pn, oldpn));
  accepted_pn_from = last_committed;
  num_las
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值