一、快速了解Raft算法
Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它。为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导选取(leader selection)、日志复制(log replication)、安全(safety),并且使用了更强的一致性来减少了必须需要考虑的状态。
相比Paxos,Raft算法理解起来更加直观。
Raft算法将Server划分为3种状态,或者也可以称作角色:
状态或者说角色的流转如下:
在Raft中,问题分解为:领导选取、日志复制、安全和成员变化。
复制状态机通过复制日志来实现:
1. Raft算法选主流程
Raft中有Term的概念,Term类比中国历史上的朝代更替,Raft 算法将时间划分成为任意不同长度的任期(term)。
2. 选举流程:
二、Nacos中的CP一致性
Spring Cloud Alibaba Nacos 在 1.0.0 正式支持 AP 和 CP 两种一致性协议,其中的CP一致性协议实现,是基于简化的 Raft 的 CP 一致性。
如何实现Raft算法
Nacos server在启动时,会通过RunningConfig.onApplicationEvent()方法调用RaftCore.init()方法。
启动选举
- public static void init() throws Exception {
- Loggers.RAFT.info("initializing Raft sub-system");
- // 启动Notifier,轮询Datums,通知RaftListener
- executor.submit(notifier);
- // 获取Raft集群节点,更新到PeerSet中
- peers.add(NamingProxy.getServers());
- long start = System.currentTimeMillis();
- // 从磁盘加载Datum和term数据进行数据恢复
- RaftStore.load();
- Loggers.RAFT.info("cache loaded, peer count: {}, datum count: {}, current term: {}",
- peers.size(), datums.size(), peers.getTerm());
- while (true) {
- if (notifier.tasks.size() <= 0) {
- break;
- }
- Thread.sleep(1000L);
- System.out.println(notifier.tasks.size());
- }
- Loggers.RAFT.info("finish to load data from disk, cost: {} ms.", (System.currentTimeMillis() - start));
- GlobalExecutor.register(new MasterElection()); // Leader选举
- GlobalExecutor.register1(new HeartBeat()); // Raft心跳
- GlobalExecutor.register(new AddressServerUpdater(), GlobalExecutor.ADDRESS_SERVER_UPDATE_INTERVAL_MS);
- if (peers.size() > 0) {
- if (lock.tryLock(INIT_LOCK_TIME_SECONDS, TimeUnit.SECONDS)) {
- initialized = true;
- lock.unlock();
- }
- } else {
- throw new Exception("peers is empty.");
- }
- Loggers.RAFT.info("timer started: leader timeout ms: {}, heart-beat timeout ms: {}",
- GlobalExecutor.LEADER_TIMEOUT_MS, GlobalExecutor.HEARTBEAT_INTERVAL_MS);
- }
在init方法主要做了如下几件事:
选举流程
其中,raft集群内部节点间是通过暴露的Restful接口,代码在 RaftController 中。RaftController控制器是raft集群内部节点间通信使用的,具体的信息如下:
- POST HTTP://{ip:port}/v1/ns/raft/vote : 进行投票请求
- POST HTTP://{ip:port}/v1/ns/raft/beat : Leader向Follower发送心跳信息
- GET HTTP://{ip:port}/v1/ns/raft/peer : 获取该节点的RaftPeer信息
- PUT HTTP://{ip:port}/v1/ns/raft/datum/reload : 重新加载某日志信息
- POST HTTP://{ip:port}/v1/ns/raft/datum : Leader接收传来的数据并存入
- DELETE HTTP://{ip:port}/v1/ns/raft/datum : Leader接收传来的数据删除操作
- GET HTTP://{ip:port}/v1/ns/raft/datum : 获取该节点存储的数据信息
- GET HTTP://{ip:port}/v1/ns/raft/state : 获取该节点的状态信息{UP or DOWN}
- POST HTTP://{ip:port}/v1/ns/raft/datum/commit : Follower节点接收Leader传来得到数据存入操作
- DELETE HTTP://{ip:port}/v1/ns/raft/datum : Follower节点接收Leader传来的数据删除操作
- GET HTTP://{ip:port}/v1/ns/raft/leader : 获取当前集群的Leader节点信息
- GET HTTP://{ip:port}/v1/ns/raft/listeners : 获取当前Raft集群的所有事件监听者
- RaftPeerSet
心跳机制
Raft中使用心跳机制来触发leader选举。心跳定时任务是在GlobalExecutor 中,通过 GlobalExecutor.register(new HeartBeat())注册心跳定时任务,具体操作包括:
- public class HeartBeat implements Runnable {
- @Override
- public void run() {
- try {
- if (!peers.isReady()) {
- return;
- }
- RaftPeer local = peers.local();
- local.heartbeatDueMs -= GlobalExecutor.TICK_PERIOD_MS;
- if (local.heartbeatDueMs > 0) {
- return;
- }
- local.resetHeartbeatDue();
- sendBeat();
- } catch (Exception e) {
- Loggers.RAFT.warn("[RAFT] error while sending beat {}", e);
- }
- }
- }
简单说明了下Nacos中的Raft一致性实现,更详细的流程,可以下载源码,查看 RaftCore 进行了解。源码可以通过以下地址检出:
- git clone https://github.com/alibaba/nacos.git
4 月 25 日消息 谷歌在本周发布了 Android 12 开发者预览 Beta 3 更新,该更新是...
今日,微信发布了 iOS 版 8.0.3 正式版更新。更新日志显示,此次更新内容为 解决...
我的手机右上角出现5G标识,是不是意味着正在使用5G网络?可我并没有办理5G套餐,...
人类是感性生物,眼睛对于图像捕捉的兴趣程度往往是大于文本的。也正是因为应用...
从2017年国务院发布《关于深化互联网+先进制造业发展工业互联网的指导意见》,到...
微信功能之强大,大家可是有目共睹。除了庞大的用户基数外,还有一个亮点我觉得...
用过 webpack 的同学肯定知道 webpack-bundle-analyzer ,可以用来分析当前项目 ...
电子产品在十年里,尤其是手机行业,兴衰起落。例如当初的手机霸主诺基亚,被初...
本文转载自公众号读芯术(ID:AI_Discovery) 为什么我对深度学习的关注重点转向图...
分析聊天机器人,因其是在现实生活中利用人工智能最流行,被最广泛采用和使用门...