braft中AppendEntries逻辑

————————————————————————————————————————————————————————————————————————————————————————————————

1.
becom_leader
_replicator_group.add_replicator(peer);
对每个follower启动一个heartbeat timer
Replicator::start()
_ballot_box//这个是leader节点针对logEntry的投票
r->_next_index为当前leader的中log_manager中获取的
r->_send_empty_entries(false) // false表示的是非heartbeat,
目的是为了让每个peer变为follower,以及更新对每个follwer的next_index
bthread_timer_add(_heartbeat_timer, _on_timeout);

初始化ballot_box中的pending_index为_log_manager->last_log_index() + 1

pending_index之前的LogEntry已经leader本地持久化的WAL
————————————————————————————————————————————————————————————————————————————————————————————————


2.void send_empty_entries(bool heartbeat);

_fill_common_fields判断是否需要安装快照_install_snapshot
这个函数会有两情况会调用
1.heartbeat timeout超时, closuer回调函数_on_heartbeat_returned
2.一个node刚成为leader的时候,需要通知所有的peer,告诉他们我是leader,更新到每个peer的next_index,同步peer的next_index
回调函数_on_rpc_returned
请求主要参数:prev_log_index(当前leader的next_index-1)
prev_log_term(leader从log_manager中获取),term
_append_entries_in_fly(_next_index, 0/*entry_size*/, cntl->call_id())
————————————————————————————————————————————————————————————————————————————————————————————————


3.on_rpc_returned
为append_entries的APRPC请求,这块是关于no op的response的解释
【1】如果response->success为false
(1)response->term > r->options.term当前的这个leader需要step_down为follower状态
node_impl->increase_term_to(response->term(), status);
(2)这个leader刚上任,在log recover中.follower的日志跟prev_log_index和prev_log_term不匹
if (response->last_log_index() + 1 < r->_next_index) {
    r->_next_index = response->last_log_index() + 1;
} else {
    —r->_next_index;
}
重新发送r->send_empty_entries(false);目的是为了log_recover

【2】这个中情况一般是非no op的response
Request->entries > 0
r->_options.ballot_box->commit_at(min_flying_index, rpc_last_log_index)

min_flying_index表示leader与这个follower首个没有确认granted的位置,由_next_index-_flying_append_entries_size得到

 rpc_last_log_index = request->prev_log_index() + entries_size;当前这个rpc确认的success的LogEntry,

follower确认表示[max(pending_index,min_flying_index), rpc_last_log_index]都是确认的

更新commit_index,next_index
ball_box达到granted会调用FsmCaller::on_committed,会调用应用层的on_apply()
【3】如果一切顺利的话,会调用Replicator::_send_entries发起正式的appendEntries

一开始发送空的entries有两个作用:
1、向follower声明自己的身份,让他们设置_leader_id
2、得到follower的正确_next_index。 
————————————————————————————————————————————————————————————————————————————————————————————————

4.send_entries
 (1)调用_fill_common_fields填充request,如果填充失败,意味着当前index为0,需要安装快照。然后计算max_entries_size,并调用_prepare_entry获取entry并添加到request中。
_prepare_entry会从logManager获取entry,首先从缓存获取,失败则从文件获取。
(2)如果request->entries_size()为0,调用Replicator::_wait_more_entries去等待新的任务到来。 如果有新的log过来,就会调用_continue_sending继续_send_entries。
_wait_more_entries将r->_id注册到log_manager中
_options.log_manager->wait(_next_index - 1, _continue_sending, (void*)_id.value);
等真正有client发起请求时候:
nodeimpl->apply() —>_ballot_box->append_pending_task对当前元素位置创建一个ballot

-> LogManager会调用append_entries. —->LogManager::wakeup_all_waiter会给每个follower启动一个bthread执行_continue_sending发送LogEntries(APRPC请求),这些APRPC请求的Closure是_on_rpc_returened(也会执行_ballot_box->commit_at)
还有一个closure是leader自己写本地存储log_entry成功后,调用LeaderStableClosure,执行_ballot_box->commit_at->commit_at处理_pending_meta_queue
————————————————————————————————————————————————————————————————————————————————————————————————
5.follwer收到APRPC,append_entries
Nodeimpl->handle_append_entries_request
主要是解析cntl->request_attachment中内容为LogEntry
log_manager->append_entries(done)
【1】append_entries中check_and_resolve_conflict解决LogEntry冲突
【2】回调函数是FollowerStableClosureFollowerStableClosure::Run()
(1)从APRPC中的committed_index调用ballot_box->set_last_committed_index
持久化成功后调用done->Run(),也就是FollowerStableClosure::Run(),该函数最后会检查一下term来判断leader有没有变化,如果一切正常,则调用BallotBox::set_last_committed_indexcommit index更新commit index
如果更新成功,就调用FsmCaller的on_committed,on_committed将构造一个任务提交到execution_queue里面,最后调用FSMCaller::do_committed去调用用户传入的自定义的StateMachine::on_apply函数执行状态机的操作。
(2)构造APRC的respnse

6.leader收到APRPC的response
当follower返回RPC后会调用_on_rpc_returned,前面的部分和空的rpc一样,但是有一个分支不一样,它会调用BallotBox::commit_at去投票并决定是否更新commit index
首先从 _pending_meta_queue取出对应的Ballot,然后调用Ballot::grant把_quorum减一,然后判断bl.granted(),如果_quorum小于等于0则返回true。_quorum代表着majority,是peer数量的一半加一。如果granted了,就表明majority达成一致,更新_last_committed_index,并调用就调用FsmCaller的on_committed去执行状态机的操作,和follower的提交类似。

参考https://zhuanlan.zhihu.com/p/169904153

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值