前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊nacos RaftCore的MasterElection

聊聊nacos RaftCore的MasterElection

原创
作者头像
code4it
修改2019-10-08 10:47:15
4180
修改2019-10-08 10:47:15
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下nacos RaftCore的MasterElection

RaftCore

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java

代码语言:javascript
复制
@Component
public class RaftCore {
    
    //......
​
    @PostConstruct
    public void init() throws Exception {
​
        Loggers.RAFT.info("initializing Raft sub-system");
​
        executor.submit(notifier);
​
        long start = System.currentTimeMillis();
​
        raftStore.loadDatums(notifier, datums);
​
        setTerm(NumberUtils.toLong(raftStore.loadMeta().getProperty("term"), 0L));
​
        Loggers.RAFT.info("cache loaded, datum count: {}, current term: {}", datums.size(), peers.getTerm());
​
        while (true) {
            if (notifier.tasks.size() <= 0) {
                break;
            }
            Thread.sleep(1000L);
        }
​
        initialized = true;
​
        Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start));
​
        GlobalExecutor.registerMasterElection(new MasterElection());
        GlobalExecutor.registerHeartbeat(new HeartBeat());
​
        Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}",
            GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS);
    }
​
    //......
}
  • RaftCore的init方法通过GlobalExecutor.registerMasterElection(new MasterElection())注册了MasterElection

GlobalExecutor

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/misc/GlobalExecutor.java

代码语言:javascript
复制
public class GlobalExecutor {
​
    //......
​
    public static final long TICK_PERIOD_MS = TimeUnit.MILLISECONDS.toMillis(500L);
​
    public static void registerMasterElection(Runnable runnable) {
        executorService.scheduleAtFixedRate(runnable, 0, TICK_PERIOD_MS, TimeUnit.MILLISECONDS);
    }
​
    //......
}
  • registerMasterElection方法每隔TICK_PERIOD_MS毫秒调度一次runnable

MasterElection

nacos-1.1.3/naming/src/main/java/com/alibaba/nacos/naming/consistency/persistent/raft/RaftCore.java

代码语言:javascript
复制
    public class MasterElection implements Runnable {
        @Override
        public void run() {
            try {
​
                if (!peers.isReady()) {
                    return;
                }
​
                RaftPeer local = peers.local();
                local.leaderDueMs -= GlobalExecutor.TICK_PERIOD_MS;
​
                if (local.leaderDueMs > 0) {
                    return;
                }
​
                // reset timeout
                local.resetLeaderDue();
                local.resetHeartbeatDue();
​
                sendVote();
            } catch (Exception e) {
                Loggers.RAFT.warn("[RAFT] error while master election {}", e);
            }
​
        }
​
        public void sendVote() {
​
            RaftPeer local = peers.get(NetUtils.localServer());
            Loggers.RAFT.info("leader timeout, start voting,leader: {}, term: {}",
                JSON.toJSONString(getLeader()), local.term);
​
            peers.reset();
​
            local.term.incrementAndGet();
            local.voteFor = local.ip;
            local.state = RaftPeer.State.CANDIDATE;
​
            Map<String, String> params = new HashMap<>(1);
            params.put("vote", JSON.toJSONString(local));
            for (final String server : peers.allServersWithoutMySelf()) {
                final String url = buildURL(server, API_VOTE);
                try {
                    HttpClient.asyncHttpPost(url, null, params, new AsyncCompletionHandler<Integer>() {
                        @Override
                        public Integer onCompleted(Response response) throws Exception {
                            if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
                                Loggers.RAFT.error("NACOS-RAFT vote failed: {}, url: {}", response.getResponseBody(), url);
                                return 1;
                            }
​
                            RaftPeer peer = JSON.parseObject(response.getResponseBody(), RaftPeer.class);
​
                            Loggers.RAFT.info("received approve from peer: {}", JSON.toJSONString(peer));
​
                            peers.decideLeader(peer);
​
                            return 0;
                        }
                    });
                } catch (Exception e) {
                    Loggers.RAFT.warn("error while sending vote to server: {}", server);
                }
            }
        }
    }
  • MasterElection实现了Runnable方法,其run方法在peers都是ready而且local.leaderDueMs减去TICK_PERIOD_MS小于等于0的时候会开始选举;它首先resetLeaderDue及resetHeartbeatDue,然后执行sendVote方法;sendVote方法首先重置peers,递增localPeer的term,并设置voteFor为自己,然后更新state为RaftPeer.State.CANDIDATE,最后遍历peers.allServersWithoutMySelf(),将自己的vote信息异步post给其他peer;如果其他peer返回成功则执行peers.decideLeader(peer),返回1,否则返回0

小结

RaftCore的init方法通过GlobalExecutor.registerMasterElection(new MasterElection())注册了MasterElection;registerMasterElection方法每隔TICK_PERIOD_MS毫秒调度一次;MasterElection实现了Runnable方法,其run方法在peers都是ready而且local.leaderDueMs减去TICK_PERIOD_MS小于等于0的时候会开始选举;它首先resetLeaderDue及resetHeartbeatDue,然后执行sendVote方法

doc

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • RaftCore
  • GlobalExecutor
  • MasterElection
  • 小结
  • doc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档