Nacos注册表是怎么解决读写并发冲突的

Posted 抓手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nacos注册表是怎么解决读写并发冲突的相关的知识,希望对你有一定的参考价值。

Nacos在更新实例列表的时候,采用CopyOnWrite思想,将传入的实例列表List<Instance> ips与旧的实例列表比对,分别得出需要添加、更新、和删除的实例,然后做一些相关的操作,得到最终新实例列表并替换原来的旧实例列表。

更新过程中的旧实例列表不受影响,客户端依然可以读取。

源码在com.alibaba.nacos.naming.core.Cluster类下面:

    /**
     * 更新实例列表
     *
     * @param ips       实例列表
     * @param ephemeral 是否为临时实例
     */
    public void updateIps(List<Instance> ips, boolean ephemeral) 

        Set<Instance> toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances;

        // 旧的实例列表
        HashMap<String, Instance> oldIpMap = new HashMap<>(toUpdateInstances.size());
        for (Instance ip : toUpdateInstances) 
            oldIpMap.put(ip.getDatumKey(), ip);
        

        // 需要更新的实例列表
        List<Instance> updatedIPs = updatedIps(ips, oldIpMap.values());
        if (updatedIPs.size() > 0) 
            for (Instance ip : updatedIPs) 
                Instance oldIP = oldIpMap.get(ip.getDatumKey());

                // do not update the ip validation status of updated ips
                // because the checker has the most precise result
                // Only when ip is not marked, don't we update the health status of IP:
                if (!ip.isMarked()) 
                    ip.setHealthy(oldIP.isHealthy());
                

                if (ip.isHealthy() != oldIP.isHealthy()) 
                    // ip validation status updated
                    Loggers.EVT_LOG.info(" SYNC IP- :@", getService().getName(),
                            (ip.isHealthy() ? "ENABLED" : "DISABLED"), ip.getIp(), ip.getPort(), getName());
                

                if (ip.getWeight() != oldIP.getWeight()) 
                    // ip validation status updated
                    Loggers.EVT_LOG.info(" SYNC IP-UPDATED ->", getService().getName(), oldIP.toString(),
                            ip.toString());
                
            
        

        // 新增的实例列表
        List<Instance> newIPs = subtract(ips, oldIpMap.values());
        if (newIPs.size() > 0) 
            Loggers.EVT_LOG
                    .info(" SYNC IP-NEW cluster: , new ips size: , content: ", getService().getName(),
                            getName(), newIPs.size(), newIPs.toString());

            for (Instance ip : newIPs) 
                HealthCheckStatus.reset(ip);
            
        

        // 被删掉的实例列表
        List<Instance> deadIPs = subtract(oldIpMap.values(), ips);
        if (deadIPs.size() > 0) 
            Loggers.EVT_LOG
                    .info(" SYNC IP-DEAD cluster: , dead ips size: , content: ", getService().getName(),
                            getName(), deadIPs.size(), deadIPs.toString());

            for (Instance ip : deadIPs) 
                HealthCheckStatus.remv(ip);
            
        

        toUpdateInstances = new HashSet<>(ips);

        if (ephemeral) 
            ephemeralInstances = toUpdateInstances;
         else 
            persistentInstances = toUpdateInstances;
        
    

以上是关于Nacos注册表是怎么解决读写并发冲突的的主要内容,如果未能解决你的问题,请参考以下文章

微服务注册中心的注册表如何更好的防止读写并发冲突

Nacos源码系列——第二章(Nacos核心源码主线剖析下)

php中并发读写文件冲突的解决方案(文件锁应用示例)

sqlite3 解决并发读写冲突的问题

Nacos微服务注册地址为Docker内网IP的解决办法

从Nacos源码中学习代码设计之第1节-多线程CAS并发控制的使用