13、Nacos 源码分析-Distro协议(上)

本文详细分析了Nacos中Distro协议的实现,包括DistroConfig配置、DistroProtocol的核心方法,如数据同步、验证任务的启动,以及DistroComponentHolder、DistroTaskEngineHolder等组件的作用。重点探讨了服务端如何初始化、同步数据、验证数据一致性,并介绍了DistroClientDataProcessor在客户端事件处理中的角色。

应粉丝要求,想要我出一篇关于NacosDistro协议的相关内容。于是我也去研究了一下。下面分享一下我对NacosDistro协议的一些见解。如有不对之处欢迎批评指正。

本次还是以Nacos2.2.0的版本来进行分析。

首先定位一下distro的代码哪里,最简单的方法就是用IDE的查找方式,找到了两个关于distro的文件夹。

在这里插入图片描述

我们在写代码的时候按功能模块定义文件夹,可以方便我们自己和他人在快速找到相关的逻辑。

我们接着看core模块中的distro结构,它位于distributed包下面,和他同级别的还有idraft文件夹,说明这个distributed包是和分布式相关的内容,包含了distro协议,raft协议和分布式id生成的相关内容。

在这里插入图片描述

既然是分析distro协议,当然关注点在distro包中了,那从哪里开始呢?

我们看到有个DistroConfig,那就从这个开始吧,因为不管是什么逻辑代码,肯定有有一些配置项,配置信息的,我们可以通过配置信息和配置项去找到相关的逻辑和核心处理类。

在spring中,我们也可以通过分析@Configuration配置信息查看配置了一些基础信息,可以更快了了解工程的基础架构设施有哪些

DistroConfig类继承了AbstractDynamicConfig,里面也是写了几个配置信息。

public class DistroConfig extends AbstractDynamicConfig {
   
   
    
    private static final String DISTRO = "Distro";
    // 单例模式下的初始化
    private static final DistroConfig INSTANCE = new DistroConfig();
    // 同步延迟时间,默认1s
    private long syncDelayMillis = DistroConstants.DEFAULT_DATA_SYNC_DELAY_MILLISECONDS;
    // 同步超时时间,默认3s
    private long syncTimeoutMillis = DistroConstants.DEFAULT_DATA_SYNC_TIMEOUT_MILLISECONDS;
    // 同步重试延迟时间,默认3s
    private long syncRetryDelayMillis = DistroConstants.DEFAULT_DATA_SYNC_RETRY_DELAY_MILLISECONDS;
    // 验证间隔时间,默认5s
    private long verifyIntervalMillis = DistroConstants.DEFAULT_DATA_VERIFY_INTERVAL_MILLISECONDS;
    // 验证超时时间,默认3s
    private long verifyTimeoutMillis = DistroConstants.DEFAULT_DATA_VERIFY_TIMEOUT_MILLISECONDS;
    // 导入数据延迟重试时间,默认30s
    private long loadDataRetryDelayMillis = DistroConstants.DEFAULT_DATA_LOAD_RETRY_DELAY_MILLISECONDS;
    // 导入超时时间,默认30s
    private long loadDataTimeoutMillis = DistroConstants.DEFAULT_DATA_LOAD_TIMEOUT_MILLISECONDS;
    
    private DistroConfig() {
   
   
        super(DISTRO);
        resetConfig();
    }
    
    @Override
    protected void getConfigFromEnv() {
   
   
        // 省略从环境变量中获取配置信息内容
    }
    // 省略get,set和printConfig方法
}

通过对配置信息引用的查找,我们可以找到一个核心类DistroClientComponentRegistry,这个类位于com.alibaba.nacos.naming.consistency.ephemeral.distro.v2,其初始化了几个重要的与Distro相关的类。

@Component
// spring创建Bean
public class DistroClientComponentRegistry {
   
   
    private final ServerMemberManager serverMemberManager;
    private final DistroProtocol distroProtocol;
    private final DistroComponentHolder componentHolder;
    private final DistroTaskEngineHolder taskEngineHolder;
    private final ClientManager clientManager;
    private final ClusterRpcClientProxy clusterRpcClientProxy;
    // 构造方法注入
    public DistroClientComponentRegistry(ServerMemberManager serverMemberManager, DistroProtocol distroProtocol,
            DistroComponentHolder componentHolder, DistroTaskEngineHolder taskEngineHolder,
            ClientManagerDelegate clientManager, ClusterRpcClientProxy clusterRpcClientProxy) {
   
   
        this.serverMemberManager = serverMemberManager;
        this.distroProtocol = distroProtocol;
        this.componentHolder = componentHolder;
        this.taskEngineHolder = taskEngineHolder;
        this.clientManager = clientManager;
        this.clusterRpcClientProxy = clusterRpcClientProxy;
    }
    
    /**
     * 为v2的发行版协议注册必要的组件
     */
    @PostConstruct
    public void doRegister() {
   
   
        // 构造方法后执行
        DistroClientDataProcessor dataProcessor = new DistroClientDataProcessor(clientManager, distroProtocol);
        DistroTransportAgent transportAgent = new DistroClientTransportAgent(clusterRpcClientProxy,
                serverMemberManager);
        DistroClientTaskFailedHandler taskFailedHandler = new DistroClientTaskFailedHandler(taskEngineHolder);
        // 给componentHolder注册相关处理类
        componentHolder.registerDataStorage(DistroClientDataProcessor.TYPE, dataProcessor);
        componentHolder.registerDataProcessor(dataProcessor);
        componentHolder.registerTransportAgent(DistroClientDataProcessor.TYPE, transportAgent);
        componentHolder.registerFailedTaskHandler(DistroClientDataProcessor.TYPE, taskFailedHandler);
    }
}

找到了入口后,我们开始一个个分析。

#ServerMemberManager

ServerMemberManager在11、Nacos 配置服务服务端源码分析(二)这篇中已经分析了,它的主要功能是识别配置的服务端的其他节点的地址,可以支持配置在配置文件中或者单独的cluster.conf文件中,并且对文件进行了监控,发现文件数据变化的话,动态更新服务端的地址。

DistroProtocol

DistroProtocol顾明思议,这个就是DistroProtocol协议的本体。我们重点分析一下这个类。

@Component
// spring管理,由spring创建
public class DistroProtocol {
   
   
    
    private final ServerMemberManager memberManager;
    private final DistroComponentHolder distroComponentHolder;
    private final DistroTaskEngineHolder distroTaskEngineHolder;
    private volatile boolean isInitialized = false;
    
    public DistroProtocol(ServerMemberManager memberManager, DistroComponentHolder distroComponentHolder,
            DistroTaskEngineHolder distroTaskEngineHolder) {
   
   
        this.memberManager = memberManager;
        this.distroComponentHolder = distroComponentHolder;
        this.distroTaskEngineHolder = distroTaskEngineHolder;
        // 构造方法开始执行Distro协议任务
        startDistroTask();
    }
    
    private void startDistroTask() {
   
   
        if (EnvUtil.getStandaloneMode()) {
   
   
            // 单机模式无需使用Distro协议
            isInitialized = true;
            return;
        }
        // 开启验证
        startVerifyTask();
        // 开启导入
        startLoadTask();
    }
    
    private void startLoadTask() {
   
   
        // 回调函数,如果导入数据成功,说明已经初始化,否则为false
        DistroCallback loadCallback = new DistroCallback() {
   
   
            @Override
            public void onSuccess() {
   
   
                isInitialized = true;
            }
            
            @Override
            public void onFailed(Throwable throwable) {
   
   
                isInitialized = false;
            }
        };
        // 执行数据加载导入,只执行一次
        GlobalExecutor.submitLoadDataTask(
                new DistroLoadDataTask(memberManager, distroComponentHolder, DistroConfig.getInstance(), loadCallback));
    }
    
    private void startVerifyTask() {
   
   
        // 固定每次间隔5s执行验证处理
        GlobalExecutor.schedulePartitionDataTimedSync(new DistroVerifyTimedTask(memberManager, distroComponentHolder,
                        distroTaskEngineHolder.getExecuteWorkersManager()),
                DistroConfig.getInstance().getVerifyIntervalMillis());
    }
    
    public boolean isInitialized() {
   
   
        return isInitialized;
    }
    
    /**
     * 通过配置的延迟开始同步,默认1s
     */
    public void sync(DistroKey distroKey, DataOperation action) {
   
   
        sync(distroKey, action, DistroConfig.getInstance().getSyncDelayMillis());
    }
    
    /**
     * 将数据同步到所有远程服务器
     */
    public void sync(DistroKey distroKey, DataOperation action, long delay) {
   
   
        for (Member each : memberManager.allMembersWithoutSelf()) {
   
   
            syncToTarget(distroKey, action, each.getAddress(), delay);
        }
    }
    
    /**
     * 同步到目标服务器
     */
    public void syncToTarget(DistroKey distroKey, DataOperation action, String targetServer, long delay) {
   
   
        DistroKey distroKeyWithTarget = new DistroKey(distroKey.getResourceKey(), distroKey.getResourceType(),
                targetServer);
        DistroDelayTask distroDelayTask = new DistroDelayTask(distroKeyWithTarget, action, delay);
        distroTaskEngineHolder.getDelayTaskExecuteEngine().addTask(distroKeyWithTarget, distroDelayTask);
        if (Loggers.DISTRO.isDebugEnabled()) {
   
   
            Loggers.DISTRO.debug("[DISTRO-SCHEDULE] {} to {}", distroKey, targetServer);
        }
    }
    
    /**
     * 从指定服务器查询数据
     */
    public DistroData queryFromRemote(DistroKey distroKey) {
   
   
        if (null == distroKey.getTargetServer()) {
   
   
            Loggers.DISTRO.warn("[DISTRO] Can't query data from empty server");
            return null;
        }
        String resourceType = distroKey.getResourceType();
        DistroTransportAgent transportAgent = distroComponentHolder.findTransportAgent(resourceType);
        if (null == transportAgent) {
   
   
            Loggers.DISTRO.warn("[DISTRO] Can't find transport agent for key {}", resourceType);
            return null;
        }
        return transportAgent.getData(distroKey, distroKey.getTargetServer());
    }
    
    /**
     * 接收同步的distro数据,查找响应的处理器的处理
     */
    public boolean onReceive(DistroData distroData) {
   
   
        Loggers.DISTRO.info("[DISTRO] Receive distro data type: {}, key: {}", distroData.getType(),
                distroData.getDistroKey());
        String resourceType = distroData.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值