ETCD《十》-- member操作

Add Member

添加节点的一般步骤

  • 在集群里执行:etcdctl member add <new-name> --peer-urls=https://<new-ip>:2380

  • 正常情况下会返回集群的相关信息

ETCD_NAME="new-member"
ETCD_INITIAL_CLUSTER="old1=https://old1:2380,old2=https://old2:2380,new-member=https://new-ip:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://new-ip:2380"
  • 使用上面的集群信息启动新的节点
--name=<new-name>
--initial-cluster=<返回的 initial cluster>
--initial-advertise-peer-urls=https://<new-ip>:2380
--listen-peer-urls=https://<new-ip>:2380
--initial-cluster-state=existing
--data-dir=<空目录>

raft

raft消息

新的 Member 信息包装成 raftpb.ConfChangeAddNode 类型的配置变更 ConfChange

b, err := json.Marshal(memb)
cc := raftpb.ConfChange{
        Type:    raftpb.ConfChangeAddNode,
        NodeID:  uint64(memb.ID),
        Context: b,
    }

如果添加的是Learn 节点,那么类型配置变更 ConfChange 的类型为 raftpb.ConfChangeAddLearnerNode

if memb.IsLearner {
        cc.Type = raftpb.ConfChangeAddLearnerNode
    }

这个配置变更也会被包装为 pb.MsgProp 类型的消息 Propose 到 raft 流程里

pb.Message{Type: pb.MsgProp, Entries: []pb.Entry{{Type: EntryConfChange, Data: data}}}

一样的,这条消息也会经过 raft 流程追加 entry 的方式,直到超过半数节点对这个 index 进行 commit

apply配置

消息通过了 raft 流程后,集群所有节点都会在上层 server 进行 apply;

apply 配置和 apply kv 有一点区别

apply 配置其实就是将新的节点加入到每个节点的type ProgressMap map[uint64]*Progress,可以参考ETCD《四》--成为Leader

然后再将新的节点信息保存在 boltdb 中;保存在 members 这个 Bucket中,key就是member_id,value就是 member 信息

tx.UnsafePut(Members, mkey, mvalue)

然后会添加这个新的节点的 peer_url 来作为新的 Peer;会不断尝试 dail 这个新 Peer 的地址

Learner节点

Learner节点最大的区别在于加入集群后不会主动发起投票;只会接收 Leader 节点的日志同步消息

func (r *raft) tickElection() {
    r.electionElapsed++

    if !pr.IsLearner {
        r.electionElapsed = 0
        if err := r.Step(pb.Message{From: r.id, Type: pb.MsgHup}); err != nil {
        }
    }
}

集群内默认情况下最多允许 1 个 Learner 节点

Leader 节点通过 HeartBeat 向这个 Learner 节点同步 commit index;这里取得是 Learner 节点反馈给 Leader 节点的 commit index 以及 Leader 节点当前的 commit index 中的较小值,Learner 节点刚加入时肯定是更小的

func (r *raft) sendHeartbeat(to uint64, ctx []byte) {
    pr := r.trk.Progress[to]
    commit := min(pr.Match, r.raftLog.committed)
    r.send(pb.Message{
        To:      to,
        Type:    pb.MsgHeartbeat,
        Commit:  commit,
        Context: ctx,
    })
    pr.SentCommit(commit)
}

Leader 节点收到 Learner 节点的 HeartBeat 响应后;如果 Learner 节点的 commit index 仍然落后,会向这个节点同步日志

case pb.MsgHeartbeatResp:
        if pr.Match < r.raftLog.lastIndex() || pr.State == tracker.StateProbe {
            r.sendAppend(m.From)
        }

如果这个节点的 commit index 落后太多,已经被 Leader 节点 compact 了,那么就无法确定这个 index 所属的 term了,会抛出 ErrCompacted 错误

prevTerm, err := r.raftLog.term(prevIndex)
    if err != nil {
        // The log probably got truncated at >= pr.Next, so we can't catch up the
        // follower log anymore. Send a snapshot instead.
        return r.maybeSendSnapshot(to, pr)
    }
  • 在错误的情况下 ,Leader 会改为发送 snapshot 给该节点
pr.ResetState(StateSnapshot)
    pr.PendingSnapshot = snapshoti
    pr.Next = snapshoti + 1
    pr.sentCommit = snapshoti

r.send(pb.Message{To: to, Type: pb.MsgSnap, Snapshot: &snapshot})
  • 其它正常情况下,Learner 没有落后太多的话,就还是正常同步日志 entry
r.send(pb.Message{
        To:      to,
        Type:    pb.MsgApp,
        Index:   prevIndex,
        LogTerm: prevTerm,
        Entries: ents,
        Commit:  r.raftLog.committed,
    })

Promote Member

用于将 Learner 节点提升为投票节点

本质上也是再次发送一次 raftpb.ConfChangeAddNode 类型配置变更;携带了IsPromote=true

b := membership.ConfigChangeContext{
        Member: membership.Member{
            ID: types.ID(id),
        },
        IsPromote: true,
    }

cc := raftpb.ConfChange{
        Type:    raftpb.ConfChangeAddNode,
        NodeID:  id,
        Context: b,
    }

同时仅 Leader 节点能够处理 Promote 请求;Followers 收到后需要将请求通过 post http /members/promote/member_id发送给 Leader;并等待 Leader 的处理结果

for _, url := range leader.PeerURLs {
            resp, err := promoteMemberHTTP(cctx, url, id, s.peerRt)

Leader Promote 节点时会检查 Learner 节点到 Leader 节点之间的日志同步进度,至少需要同步 90% 才能 Promote 这个 Learner;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容