etcd中raft协议的消息(六)——客户端的写请求相关的消息(MsgProp消息)
在etcd-raft模块中,客户端发往集群中的写请求是通过MsgProp消息表示的。Raft集群中只有Leader节点能够响应客户端的写入请求。
客户端请求的写操作,会通过调用Node接口的Propose函数请求到raft模块中,当Follower接收到MsgProp类型的消息会转发到Leader节点,所以MsgProp消息的主要处理是在raft.stepLeader()方法中实现。主要流程如下:
1.判断MsgProp是否携带Entry记录,如果未携带则输出异常日志并终止程序
2.检测当前节点是否被移除集群,如果当前节点以Leader状态被移除集群,则不再处理MsgProp消息
3.判断当前是否正在进行Leader节点转移,如果正在转移则返回错误
4.遍历MsgProp消息携带的全部Entry,如果pendingConfIndex大于已提交的位置,则该Entry的类型设置为EntryNormal,否则更新pendingConfIndex值
5.将上述Entries记录追加到当前节点的raftLog中
6.向集群中的其他节点发送MspApp消息复制日志
func stepLeader(r *raft, m pb.Message) error {
switch m.Type {
//其他消息省略.....
case pb.MsgProp:
if len(m.Entries) == 0 { //判断MsgProp是否携带Entry记录,如果未携带则输出异常日志并终止程序
r.logger.Panicf("%x stepped empty MsgProp", r.id)
}
if _, ok := r.prs[r.id]; !ok { //检测当前节点是否被移除集群,如果当前节点以Leader状态被移除集群,则不再处理MsgProp消息
// If we are not currently a member of the range (i.e. this node
// was removed from the configuration while serving as leader),
// drop any new proposals.
return ErrProposalDropped
}
if r.leadTransferee != None { //判断当前是否正在进行Leader节点转移
r.logger.Debugf("%x [term %d] transfer leadership to %x is in progress; dropping proposal", r.id, r.Term, r.leadTransferee)
return ErrProposalDropped
}
for i, e := range m.Entries { //遍历MsgProp消息携带的全部Entry
if e.Type == pb.EntryConfChange {
if r.pendingConfIndex > r.raftLog.applied {
r.logger.Infof("propose conf %s ignored since pending unapplied configuration [index %d, applied %d]",
e.String(), r.pendingConfIndex, r.raftLog.applied)
m.Entries[i] = pb.Entry{Type: pb.EntryNormal}
} else {
r.pendingConfIndex = r.raftLog.lastIndex() + uint64(i) + 1
}
}
}
r.appendEntry(m.Entries...) //将上述Entry记录追加到当前节点的raftLog中
r.bcastAppend() //向集群中的其他节点发送MspApp消息复制日志
return nil
}
}