更多 blog 见: https://joeylichang.github.io/
本篇文章介绍一下PhxPaxos-Learn的过程,Learn主要的功能是追数据,追数据分为两部分,如果数据差距过大进行批量追加即ckpt(下片文章介绍),本篇文章主要介绍差距没有超过设定的闸值时,追条数据追加的过程。
PhxPaxos在追数据的过程模拟了TCP的三次握手和ACK机制,下面看一下简单的示意图:
有了上面主要流程的示意图,下面看一下时序图:
接下来分三个阶段进行介绍:
- 初始化阶段
Reset_AskforLearn_Noop主要是保证周期性的调用AskforLearn,AskforLearn向其他节点发送PaxosLearner_AskforLearn消息,进行起一次握手,没设么重要内容,下面直接看握手过程
- 协商阶段(三次握手)
第一次握手:
void Learner :: AskforLearn()
{
BP->GetLearnerBP()->AskforLearn();
PLGHead("START");
PaxosMsg oPaxosMsg;
oPaxosMsg.set_instanceid(GetInstanceID());
oPaxosMsg.set_nodeid(m_poConfig->GetMyNodeID());
oPaxosMsg.set_msgtype(MsgType_PaxosLearner_AskforLearn);
if (m_poConfig->IsIMFollower())
{
//this is not proposal nodeid, just use this val to bring followto nodeid info.
oPaxosMsg.set_proposalnodeid(m_poConfig->GetFollowToNodeID());
}
PLGHead("END InstanceID %lu MyNodeID %lu", oPaxosMsg.instanceid(), oPaxosMsg.nodeid());
// 这里有一点不是很理解,为什么tmp节点用udp,其他节点用tcp
// 可能是不想tmp节点的数据,与其他工作节点的数据一起通过一个线程发送,加快性能?
BroadcastMessage(oPaxosMsg, BroadcastMessage_Type_RunSelf_None, Message_SendType_TCP);
BroadcastMessageToTempNode(oPaxosMsg, Message_SendType_UDP);
}
第一次握手只是向其他节点发起了MsgType_PaxosLearner_AskforLearn请求。
第二次握手:
下面看一下,其他节点对MsgType_PaxosLearner_AskforLearn消息的处理:
void Learner :: OnAskforLearn(const PaxosMsg & oPaxosMsg)
{
BP->GetLearnerBP()->OnAskforLearn();
PLGHead("START Msg.InstanceID %lu Now.InstanceID %lu Msg.from_nodeid %lu MinChosenInstanceID %lu",
oPaxosMsg.instanceid(), GetInstanceID(), oPaxosMsg.nodeid(),
m_poCheckpointMgr->GetMinChosenInstanceID());
// 更新当前节点视角下的paxos-group信息
SetSeenInstanceID(oPaxosMsg.instanceid(), oPaxosMsg.nodeid());
// 注意:在learn请求中proposalnodeid 不为0表示,发送请求的节点是fllower
if (oPaxosMsg.proposalnodeid() == m_poConfig->GetMyNodeID())
{
//Found a node follow me.
PLImp("Found a node %lu follow me.", oPaxosMsg.nodeid());
m_poConfig->AddFollowerNode(oPaxosMsg.nodeid());
}
// 表示对端节点数据比当前节点新
if (oPaxosMsg.instanceid() >= GetInstanceID())
{
return;
}
// 节点数据落后过多,走ckpt逻辑(下篇文章介绍)
if (oPaxosMsg.instanceid() >= m_poCheckpointMgr->GetMinChosenInstanceID())
{
if (!m_oLearnerSender.Prepare(oPaxosMsg.instanceid(), oPaxosMsg.nodeid()))
{
BP->GetLearnerBP()->OnAskforLearnGetLockFail();
PLGErr("LearnerSender working for others.");
if (oPaxosMsg.instanceid() == (GetInstanceID() - 1))
{
PLGImp("InstanceID only difference one, just send this