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 协议最关键的部分是每个节点只负责一部分写数据。

相关推荐
zb200641202 小时前
CVE-2024-38819:Spring 框架路径遍历 PoC 漏洞复现
java·后端·spring
uzong2 小时前
AI Agent 是什么,如何理解它,未来挑战和思考
人工智能·后端·架构
追逐时光者3 小时前
DotNetGuide突破了10K + Star,一份全面且免费的C#/.NET/.NET Core学习、工作、面试指南知识库!
后端·.net
yuweiade3 小时前
springboot和springframework版本依赖关系
java·spring boot·后端
ywf12153 小时前
springboot设置多环境配置文件
java·spring boot·后端
小马爱打代码3 小时前
SpringBoot + 消息生产链路追踪 + 耗时分析:从创建到发送,全链路性能可视化
java·spring boot·后端
小码哥_常3 小时前
MyBatis批量插入:从5分钟到3秒的逆袭之路
后端
烛之武5 小时前
SpringBoot基础
java·spring boot·后端
橙序员小站5 小时前
Harness Engineering:从 OpenClaw 看 AI 助理的基础设施建设
后端·aigc·openai
小陈工5 小时前
2026年3月28日技术资讯洞察:5G-A边缘计算落地、低延迟AI推理革命与工业智造新范式
开发语言·人工智能·后端·python·5g·安全·边缘计算