Nacos Distro 一致性协议

这篇文章要分享的是 Nacos 集群的 Distro一致性协议。

如下图所示,Nacos Client 向 Nacos Server 集群中的一个服务节点注册信息,这些服务端节点之间再进行数据同步,应用的基础原理就是 Distro 一致性协议。

Distro一致性协议

Distro 协议是 Nacos 对于临时实例数据开发的一致性协议,是阿里巴巴的私有协议。

Distro 的设计机制

新节点同步机制:Nacos 启动时,从其他节点同步数据。

平等机制:Nacos 的每个节点是平等的,都可以处理写的请求。

路由转发机制:客户端发送的写请求,如果属于自己则处理,否则路由转发给其他节点。

异步复制机制:Nacos 把变更的数据异步复制到其他节点。

健康检查机制:每个节点只存了部分数据,定期检查客户端状态保持数据一致性。

本地读机制: 每个节点独立处理读请求,及时从本地发出响应。

Nacos 源码解析

接下来就从 Nacos 源码的角度来学习 Distro 的原理。

新节点同步机制

com.alibaba.nacos.core.distributed.distro.DistroProtocol#startLoadTask

如果此时新加入一个 Nacos Server 节点,会同步从其他节点拉取数据。

java 复制代码
GlobalExecutor.submitLoadDataTask(
                new DistroLoadDataTask(memberManager, distroComponentHolder, DistroConfig.getInstance(), loadCallback));          

看到线程池,便知道这是一个异步任务。

java 复制代码
load();
if (!checkCompleted()) {
   GlobalExecutor.submitLoadDataTask(this, distroConfig.getLoadDataRetryDelayMillis());
} else {
   loadCallback.onSuccess();
   Loggers.DISTRO.info("[DISTRO-INIT] load snapshot data success");
}

一上来先拉取其他节点的数据,只要有一个成功了就算通过。之后再检查是否全量同步成功,没有的话,30秒之后再重新同步一次。

平等机制

com.alibaba.nacos.naming.web.DistroFilter

每个节点处理部分写请求,通过算法计算属于自己的请求就处理,不属于自己的请求转发到正确的节点。

java 复制代码
public boolean responsible(String responsibleTag) {
   final List<String> servers = healthyList;
   
   if (!switchDomain.isDistroEnabled() || EnvUtil.getStandaloneMode()) {
       return true;
   }
   
   if (CollectionUtils.isEmpty(servers)) {
       // means distro config is not ready yet
       return false;
   }
   
   String localAddress = EnvUtil.getLocalAddress();
   int index = servers.indexOf(localAddress);
   int lastIndex = servers.lastIndexOf(localAddress);
   if (lastIndex < 0 || index < 0) {
       return true;
   }
   
   int target = distroHash(responsibleTag) % servers.size();
   return target >= index && target <= lastIndex;
}

路由转发机制

com.alibaba.nacos.naming.web.DistroFilter

路由转发机制和平等机制为上下文关系,不是自己处理的请求,就计算出真正要处理的服务地址,然后转发给它处理。

java 复制代码
final String targetServer = distroMapper.mapSrv(distroTag);

异步复制机制

com.alibaba.nacos.core.distributed.distro.DistroProtocol#sync

如果自己所在的服务端数据发生了变更,就把数据异步复制给集群中的其他节点。

java 复制代码
public void sync(DistroKey distroKey, DataOperation action, long delay) {
    for (Member each : memberManager.allMembersWithoutSelf()) {
        syncToTarget(distroKey, action, each.getAddress(), delay);
    }
}

健康检查机制

服务端集群每个节点处理数据有快有慢,这些数据到底是否全部一致呢?这就需要健康检查机制。线程池提交异步任务,每隔5秒检查一次。

每个服务端节点只负责检查自己负责的客户端的数据是否一致,不是自己对应的客户端不处理。

java 复制代码
private void startVerifyTask() {
   GlobalExecutor.schedulePartitionDataTimedSync(new DistroVerifyTimedTask(memberManager, distroComponentHolder,
                   distroTaskEngineHolder.getExecuteWorkersManager()),
           DistroConfig.getInstance().getVerifyIntervalMillis());
}

本地读机制

com.alibaba.nacos.naming.controllers.InstanceController#list

每个服务端节点最终会存储全部的客户端数据,只要 Nacos Client 请求,会从本地直接返回数据,而不是从其他服务器拉取数据,相当于提升了服务端的响应速度。

数据全部存储在com.alibaba.nacos.naming.core.Service#clusterMap 内存集合中,所以速度非常快。

总结:Distro 协议最关键的部分是每个节点只负责一部分写数据。

相关推荐
你的人类朋友5 小时前
说说git的变基
前端·git·后端
阿杆5 小时前
玩转 Amazon ElastiCache 免费套餐:小白也能上手
后端
阿杆5 小时前
无服务器每日自动推送 B 站热门视频
后端
公众号_醉鱼Java6 小时前
Elasticsearch 字段膨胀使用 Flattened类型
后端·掘金·金石计划
JohnYan7 小时前
工作笔记 - CentOS7环境运行Bun应用
javascript·后端·容器
探索java7 小时前
Netty Channel详解:从原理到实践
java·后端·netty
追逐时光者7 小时前
2025 年全面的 C#/.NET/.NET Core 学习路线集合,学习不迷路!
后端·.net
ankleless9 小时前
Spring Boot 实战:从项目搭建到部署优化
java·spring boot·后端
百锦再9 小时前
一文精通 Swagger 在 .NET 中的全方位配置与应用
后端·ui·.net·接口·配置·swagger·访问
用户4822137167759 小时前
C++——静态数组、动态数组
后端