Nacos源码之AP一致性协议实现
admin
2024-03-18 16:23:26
0

CAP介绍

在了解Nacos一致性协议之前先了解一下CAP是什么:

C:一致性

A:可用性

P:分区容错性。针对多节点部署的系统,分区就代表了网络分区,由于网络原因节点之间无法通信进行数据同步。容错指在这种情况下,系统仍然可以对外提供服务。

在分布式系统中,首先需要保证P,然后在C和A之间做权衡:

在满足P的情况下,如果向node1写入一条数据,因为分区产生则数据无法同步给其他节点,此时就需要在C和A直接做出选择。

选择C,则需要保证所有节点数据的一致性,则整个分布式系统对外暂时不可用。

选择A,则会舍弃C,分布性系统仍然可以对外提供服务,但是因为数据没有同步,则通过不同节点查询返回的结果回不一致。

Nacos中的一致性协议

作为一个分布式系统,Nacos 的服务管理和配置管理都支持 AP、CP 协议。相比较而言Zookeeper作为服务发现常用的一种实现方式只支持CP协议。本篇还是以注册中心功能为基础进行介绍。

服务之间感知对方服务可正常提供服务的实例信息,必须从注册中心获取。因此对注册中心的可用性就会有着更高的要求,尽可能保证服务注册功能的可用性。

在Nacos中,注册中心分为非持久化和持久化两种服务:

非持久化对应了AP协议:保障服务的可用性,在一定时间内,各节点数据可以达成一致。

持久化则对应的CP协议:保障了各个节点数据的强一致性。

Nacos中AP协议的具体实现则是Distro 协议,是Nacos自研的一种协议。而CP协议的实现则是Raft协议。具体代码代码实现都在naming.consistency包中。

在Distro 协议的设计下

Nacos 每个节点是平等的都可以处理写请求,同时把新数据同步到其他节点。

每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据⼀致性。

对于读请求每个节点可以独立处理,及时从本地发出响应。

对于写请求,Nacos中会员前置Filter根据请求中包含的 IP 和 port 信息计算其所属的 Distro 责任节点, 并将该请求转发到所属的 Distro 责任节点上。

Distro协议源码分析

在之前我们已经知道了,Nacos注册中心实现的大体流程,最终的数据存储在ServiceManager类中的双层Map中,之后就会通知客户端,推送最新的实例信息。

/*** Map(namespace, Map(group::serviceName, Service)).*/
private final Map> serviceMap = new ConcurrentHashMap<>();
复制代码

在往Service模型中添加实例(**ServiceManager.**addInstance)的时候调用了:

consistencyService.put(key, instances);
复制代码

这里的ConsistencyService就是我们需要关注的重点了。首先ConsistencyService接口具有多个实现类,那么在调用上面方法的时候到底是哪个实现类?通过注入的name可以发现其实是DelegateConsistencyServiceImpl:

@Resource(name = "consistencyDelegate")
private ConsistencyService consistencyService;//实现类
@DependsOn("ProtocolManager")
@Service("consistencyDelegate")
public class DelegateConsistencyServiceImpl  ...//在DelegateConsistencyServiceImpl中定义了两种实现类
private final PersistentConsistencyServiceDelegateImpl persistentConsistencyService;private final EphemeralConsistencyService ephemeralConsistencyService;@Override
public void put(String key, Record value) throws NacosException {mapConsistencyService(key).put(key, value);
}private ConsistencyService mapConsistencyService(String key) {return KeyBuilder.matchEphemeralKey(key) ? ephemeralConsistencyService : persistentConsistencyService;
}
复制代码

通过上面的代码可以知道,在非持久化的情况下,真正的实现类是ephemeralConsistencyService。而ephemeralConsistencyService具有一个唯一的实现类就是DistroConsistencyServiceImpl。到此就对应了上面所说的非持久化对应了AP协议,AP协议的具体实现则是Distro 协议。

Distro协议下完整的的put方法如下:

@Override
public void put(String key, Record value) throws NacosException {onPut(key, value);// If upgrade to 2.0.X, do not sync for v1.if (ApplicationUtils.getBean(UpgradeJudgement.class).isUseGrpcFeatures()) {return;}distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,DistroConfig.getInstance().getSyncDelayMillis());
}
复制代码

可以看到在onPut之后,调用了distroProtocol.sync方法,这个方法就是用来像其他节点同步当前节点注册实例数据用的,可以保证每个节点都有全量的注册实例信息,具体实现:

/*** Start to sync data to all remote server.** @param distroKey distro key of sync data* @param action    the action of data operation* @param delay     delay time for sync*/
public void sync(DistroKey distroKey, DataOperation action, long delay) {//遍历除当前节点之外所有的集群节点for (Member each : memberManager.allMembersWithoutSelf()) {syncToTarget(distroKey, action, each.getAddress(), delay);}
}
复制代码

到这里我们发现执行sync方法的是DistroProtocol,它是个什么东西呢?它其实就是整个Distro协议的入口。其中实现了集群多节点之间同步数据所需要的各种操作:比如初始化时向其他节点加载数据、同步数据到指定节点、获取当前节点的快照数据。

这里简单看一下新加入节点的的初始化操作:

@Component
public class DistroProtocol {public DistroProtocol(ServerMemberManager memberManager, DistroComponentHolder distroComponentHolder,DistroTaskEngineHolder distroTaskEngineHolder) {this.memberManager = memberManager;this.distroComponentHolder = distroComponentHolder;this.distroTaskEngineHolder = distroTaskEngineHolder;startDistroTask();
}....)
复制代码

通过注解可以知道在服务启动之后就会调用startDistroTask,从集群的其他节点同步注册实例数据到当前节点,来保障集群的的每台机器上都维护了当前的所有注册上来的非持久化实例数 据:

private void load() throws Exception {while (memberManager.allMembersWithoutSelf().isEmpty()) {Loggers.DISTRO.info("[DISTRO-INIT] waiting server list init...");TimeUnit.SECONDS.sleep(1);}while (distroComponentHolder.getDataStorageTypes().isEmpty()) {Loggers.DISTRO.info("[DISTRO-INIT] waiting distro data storage register...");TimeUnit.SECONDS.sleep(1);}for (String each : distroComponentHolder.getDataStorageTypes()) {if (!loadCompletedMap.containsKey(each) || !loadCompletedMap.get(each)) {loadCompletedMap.put(each, loadAllDataSnapshotFromRemote(each));}}
}private boolean loadAllDataSnapshotFromRemote(String resourceType) {DistroTransportAgent transportAgent = distroComponentHolder.findTransportAgent(resourceType);DistroDataProcessor dataProcessor = distroComponentHolder.findDataProcessor(resourceType);if (null == transportAgent || null == dataProcessor) {Loggers.DISTRO.warn("[DISTRO-INIT] Can't find component for type {}, transportAgent: {}, dataProcessor: {}",resourceType, transportAgent, dataProcessor);return false;}for (Member each : memberManager.allMembersWithoutSelf()) {long startTime = System.currentTimeMillis();try {Loggers.DISTRO.info("[DISTRO-INIT] load snapshot {} from {}", resourceType, each.getAddress());DistroData distroData = transportAgent.getDatumSnapshot(each.getAddress());Loggers.DISTRO.info("[DISTRO-INIT] it took {} ms to load snapshot {} from {} and snapshot size is {}.",System.currentTimeMillis() - startTime, resourceType, each.getAddress(),getDistroDataLength(distroData));boolean result = dataProcessor.processSnapshot(distroData);Loggers.DISTRO.info("[DISTRO-INIT] load snapshot {} from {} result: {}", resourceType, each.getAddress(),result);if (result) {distroComponentHolder.findDataStorage(resourceType).finishInitial();return true;}} catch (Exception e) {Loggers.DISTRO.error("[DISTRO-INIT] load snapshot {} from {} failed.", resourceType, each.getAddress(), e);}}return false;
}
复制代码

可以看到这里会遍历集群其他节点进行数据的同步,具体操作是轮询所有的 Distro 节点,通过向其他的机器发送请求拉取全量数据。

DistroProtocol中还有很多其他同步数据相关的方法实现,大家可以自己结合某个点来去查看阅读。

总结

到此我们已经基本了解了Naocs中临时节点所使用的一致性协议。作为注册中心功能来说需要保证其可用性,一般会选用AP协议,也就是Distro。在Distro 协议的设计思想下,每个 Distro 节点都可以接收到读写请求,并且会全量或者定期的进行数据同步,保障集群中所有节点数据的最终一致性。

关于相关的代码,在源码中还有更多实现,大家可以自行去阅读。

相关内容

热门资讯

安卓系统的如何测试软件,从入门... 你有没有想过,你的安卓手机里那些神奇的软件是怎么诞生的呢?它们可不是凭空出现的,而是经过一系列严格的...
小米8安卓系统版本,安卓系统版... 你有没有发现,手机更新换代的速度简直就像坐上了火箭呢?这不,小米8这款手机自从上市以来,就凭借着出色...
华为手机安卓系统7以上,创新体... 你有没有发现,最近华为手机越来越受欢迎了呢?尤其是那些搭载了安卓系统7.0及以上版本的机型,简直让人...
儿童英语免费安卓系统,儿童英语... 哇,亲爱的家长朋友们,你是否在为孩子的英语学习发愁呢?别担心,今天我要给你带来一个超级好消息——儿童...
ios系统切换安卓系统还原,还... 你有没有想过,有一天你的手机从iOS系统切换到了安卓系统,然后再从安卓系统回到iOS系统呢?这听起来...
灵焕3装安卓系统,引领智能新体... 你知道吗?最近手机圈里可是掀起了一股热潮,那就是灵焕3这款神器的安卓系统升级。没错,就是那个曾经以独...
安卓系统指南针软件,探索未知世... 手机里的指南针功能是不是让你在户外探险时倍感神奇?但你知道吗,安卓系统中的指南针软件可是大有学问呢!...
华为是不用安卓系统了吗,迈向自... 最近有个大新闻在科技圈里炸开了锅,那就是华为是不是不再使用安卓系统了?这可不是一个简单的问题,它涉及...
安卓系统热点开启失败,排查与解... 最近是不是你也遇到了安卓系统热点开启失败的小麻烦?别急,让我来给你详细说说这个让人头疼的问题,说不定...
小米max2系统安卓,安卓系统... 你有没有听说过小米Max2这款手机?它那超大的屏幕,简直就像是个移动的电脑屏幕,看视频、玩游戏,那叫...
电池健康怎么保持安卓系统,优化... 手机可是我们生活中不可或缺的好伙伴,而电池健康度就是它的生命力。你有没有发现,随着使用时间的增长,你...
安卓手机怎么调系统颜色,安卓手... 你有没有发现,你的安卓手机屏幕颜色突然变得不那么顺眼了?是不是也想给它换换“脸色”,让它看起来更有个...
安卓系统清粉哪个好,哪款清粉工... 手机用久了,是不是觉得卡得要命?别急,今天就来聊聊安卓系统清理垃圾哪个软件好。市面上清理工具那么多,...
华为被限制用安卓系统,挑战安卓... 你知道吗?最近科技圈可是炸开了锅!华为,这个我们耳熟能详的名字,竟然因为一些“小插曲”被限制了使用安...
安卓系统是不是外国,源自外国的... 你有没有想过,我们每天离不开的安卓系统,它是不是外国货呢?这个问题听起来可能有点奇怪,但确实很多人都...
安卓系统缺少文件下载,全面解析... 你有没有发现,用安卓手机的时候,有时候下载个文件真是让人头疼呢?别急,今天就来聊聊这个让人烦恼的小问...
kktv系统刷安卓系统怎么样,... 你有没有听说最近KKTV系统刷安卓系统的事情?这可是个热门话题呢!咱们一起来聊聊,看看这个新玩意儿到...
安卓系统连接电脑蓝牙,操作指南... 你有没有遇到过这种情况:手机里堆满了各种好用的应用,可就是想找个方便快捷的方式,把手机里的音乐、照片...
安卓车机11.0系统包,智能驾... 你有没有发现,最近你的安卓车机系统好像悄悄升级了呢?没错,就是那个安卓车机11.0系统包!这可不是一...
安卓系统最高到多少,从初代到最... 你有没有想过,你的安卓手机系统升级到哪一步了呢?是不是好奇安卓系统最高能到多少呢?别急,今天就来带你...