对标Eureka的AP一致性,Nacos如何实现Raft算法
一、快速了解Raft算法
Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解和去实现它。
为了提高理解性,Raft 将一致性算法分为了几个部分,包括领导选取(leader selection)、日志复制(log replication)、安全(safety),并且使用了更强的一致性来减少了必须需要考虑的状态。
相比Paxos,Raft算法理解起来更加直观。
Raft算法将Server划分为3种状态,或者也可以称作角色:
Leader
负责Client交互和log复制,同一时刻系统中最多存在1个。Follower
被动响应请求RPC,从不主动发起请求RPC。Candidate
一种临时的角色,只存在于leader的选举阶段,某个节点想要变成leader,那么就发起投票请求,同时自己变成candidate。如果选举成功,则变为candidate,否则退回为follower
状态或者说角色的流转如下:

在Raft中,问题分解为:领导选取、日志复制、安全和成员变化。
复制状态机通过复制日志来实现:
日志:每台机器保存一份日志,日志来自于客户端的请求,包含一系列的命令
状态机:状态机会按顺序执行这些命令
一致性模型:分布式环境下,保证多机的日志是一致的,这样回放到状态机中的状态是一致的
Raft算法选主流程
Raft中有Term的概念,Term类比中国历史上的朝代更替,Raft 算法将时间划分成为任意不同长度的任期(term)。

选举流程
1、follower增加当前的term,转变为candidate。
2、candidate投票给自己,并发送RequestVote RPC给集群中的其他服务器。
3、收到RequestVote的服务器,在同一term中只会按照先到先得投票给至多一个candidate。且只会投票给log至少和自身一样新的candidate。
关于Raft更详细的描述,可以查看这里,从分布式一致性到共识机制(二)Raft算法
二、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集群节点 peers.add(NamingProxy.getServers());
- Raft集群数据恢复 RaftStore.load();
- Raft选举 GlobalExecutor.register(new MasterElection());
- Raft心跳 GlobalExecutor.register(new HeartBeat());
- Raft发布内容
- Raft保证内容一致性
选举流程
其中,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())注册心跳定时任务,具体操作包括:
- 重置Leader节点的heart timeout、election timeout;
- sendBeat()发送心跳包
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

扫码关注公众号:架构进化论,获得第一手的技术资讯和原创文章
对标Eureka的AP一致性,Nacos如何实现Raft算法的更多相关文章
- 分布式一致性协议之:Raft算法
一致性算法Raft详解 背景 熟悉或了解分布性系统的开发者都知道一致性算法的重要性,Paxos一致性算法从90年提出到现在已经有二十几年了,而Paxos流程太过于繁杂实现起来也比较复杂,可能也是以为过 ...
- eureka的简单介绍,eureka单节点版的实现?eureka的自我保护?eureka的AP性,和CP性?
注意!!! 这是对上一篇博客 springcloud的延续,整个项目的搭建,来源与上一篇博客.一.什么是eureka? // eureka是一个注册中心,实现了dubbo中zookeeper的效果! ...
- 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法
搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...
- 分布式一致性算法:Raft 算法(论文翻译)
Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法,而且 raft 算法比 Paxos 算法更易懂且更容易实现.本文对 raft 论文进行翻译,希望能有助于读者更方便地理解 raft 的 ...
- 从分布式一致性到共识机制(二)Raft算法
春秋五霸说开 春秋五霸,是指东周春秋时期相继称霸主的五个诸侯,“霸”,意为霸主,即是诸侯之领袖.典型的比如齐桓公,晋文公,春秋时期诸侯国的称霸,与今天要讨论的Raft算法很像. 一.更加直观的Raft ...
- 【转】分布式一致性算法:Raft 算法(Raft 论文翻译)
编者按:这篇文章来自简书的一个位博主Jeffbond,读了好几遍,翻译的质量比较高,原文链接:分布式一致性算法:Raft 算法(Raft 论文翻译),版权一切归原译者. 同时,第6部分的集群成员变更读 ...
- 理解分布式一致性与Raft算法
理解分布式一致性与Raft算法 永远绕不开的CAP定理 出于可用性及负载方面考虑,一个分布式系统中数据必然不会只存在于一台机器,一致性简单地说就是分布式系统中的各个部分保持数据一致 但让数据保持一致往 ...
- 分布式系统一致性问题与Raft算法(上)
最近在做MIT6.824的几个实验,真心觉得每一个做分布式相关开发的程序员都应该去刷一遍(裂墙推荐),肯定能够提高自己的技术认知水平,同时也非常感谢MIT能够把这么好的资源分享出来. 其中第二个实验, ...
- 分布式系统一致性问题与Raft算法(下)
上一篇讲述了什么是分布式一致性问题,以及它难在哪里,liveness和satefy问题,和FLP impossibility定理.有兴趣的童鞋可以看看分布式系统一致性问题与Raft算法(上). 这一节 ...
随机推荐
- python基础数据类型汇总
list和dict 在循环一个列表和字典时,最好不要删除其中的元素,这样会使索引发生改变,从而报错! lis = [11, 22, 33, 44, 55] for i in range(len(lis ...
- java 事件监听机制组成
事件源(组件) 事件(Event) 监听器(Listener) 事件处理(引发事件后处理方式) 事件监听机制流程图 务必记牢: 确定事件源(容器或组件) 通过事件源对象的addXXXListener( ...
- P1010 数值交换
题目描述 输入两个数 \(a\) 和 \(b\) ,将两个数交换,并输出交换后的 \(a\) 和 \(b\) . 输入格式 输入两个整数 \(a,b(1 \le a,b \le 10^6)\) 输出格 ...
- linux 快速和慢速处理
老版本的 Linux 内核尽了很大努力来区分"快速"和"慢速"中断. 快速中断是那些能够很 快处理的, 而处理慢速中断要特别地长一些. 慢速中断可能十分苛求处理 ...
- js中的函数重载
函数重载与js 什么是函数重载 重载函数是函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数.类型或者顺序)必须不同,也就是说用 ...
- linux内核指针和错误值
很多内部内核函数返回一个指针值给调用者. 许多这些函数也可能失败. 大部分情况, 失 败由返回一个 NULL 指针值来指示. 这个技术是能用的, 但是它不能通知问题的确切特性. 一些接口确实需要返回一 ...
- dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
在使用 dotnet 读写 Sqlite 可以通过 EF Core 的方法,但是在 EF Core 创建的数据库可能和读写的数据库不是相同的文件 在我运行代码的时候发现在通过迁移创建数据库,创建的文件 ...
- 2018-10-18-WPF-跨线程-UI-的方法
title author date CreateTime categories WPF 跨线程 UI 的方法 lindexi 2018-10-18 10:25:28 +0800 2018-10-18 ...
- webpack 命令
--content-base <file/directory/url/port>:内容的路径. --quiet: 在控制台不输出任何内容 --no-info: 抑制无聊的信息 --colo ...
- nodejs的nvm与.net的dnvm使用对比
一.vm安装命令 nodejs的nvm安装命令: curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.s ...