cornerstone中msg类型解析

1.概述

cornerstone中msg主要为resp_msg,req_msg类型。其中涉及到了oop中代码复用与封装、继承等优秀的设计思想,值得解析。

2.msg_base代码分析

class msg_base 
{
private:
    ulong term_;
    msg_type type_;
    int32 src_;
    int32 dst_;
}
  • 首先信息从一方发送到另一方,所以需要src_dst_
  • 在raft背景下,每条信息还需记录任期term_,同时为了支持不同消息,有消息类型type_

3. req_msg代码分析

class req_msg : public msg_base
{
private:
    ulong last_log_term_;
    ulong last_log_idx_;
    ulong commit_idx_;
    std::vector<ptr<log_entry>> log_entries_;
}
  • 为了复用代码,public继承msg_base,消息自带src_dst_term_type_
  • raft里面信息都是单向流动,只能从leader到follower。为了同步leader与follower的entry,需要leader的last_log_term_last_log_idx_以及ulong commit_idx_
  • 具体leader的entry放在log_entries_里面,如果不是为了同步entry可以为空

4. resp_msg代码分析

class resp_msg : public msg_base
{
private:
    ulong next_idx_;
    bool accepted_;
}

这里next_idx_的存在在append-entry这一个rpc通信里面很重要
在append-entry里面,follower对leader的rpc请求有两种情况

  • follower接受leader的entry
  • follower不接受leader的entry

如果是accept的情况,那么next_idx_其实是多余的,
但是如果不是accept,那么next_idx_就发挥作用了。

在raft论文里面,一个leader对每个follower都记录next_idx与match_idx。
next_idx:leader对follower应该match的idx的猜测(初始化为leader的log_store的最后idx + 1)
match_idx:leader与follower的log_store重合(即match)的idx的最大值,为实际值

举例来说:
leader:[1,2,3,4]
follower A:[1,2,3,7]
follower B:[1,3]
那么A的match_idx为2, B的match_idx为0
刚开始leader对A,B的对match_idx的猜测值next_idx都为4,即为leader的log_store的最后idx + 1。

在raft论文里给出调整next_idx的方法为next_idx每次减1,但是显然这是可以优化的。
因为在append-entry rpc中通过follower的resp,leader可以得知每个follower的log_store情况,不需要每次减1,可以一步到位。
比如对B来说,leader可以将B的next_idx缩减成B的log_store的最后idx + 1 = 2再继续逼近。
(对于A来说还是得每次减1,因为A的log_store中entry数目跟leader一样多。换句话说这种优化只针对follower的entry数目小于leader的情况。)

综上所述,在resp里面我们还需要next_idx_来帮助leader来纠正next_idx,使其更快逼近match_idx。

5.总结

  • 1.善于设计base类,利用类的继承实现base类的拓展。
  • 2.在rpc通信中,学会利用resp来传递follower的消息实现优化。
posted @ 2024-11-20 17:30  TomGeller  阅读(14)  评论(0编辑  收藏  举报