栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Nacos<四>寻址机制

Nacos<四>寻址机制

四、Nacos寻址机制 4.1单机寻址

单机模式的寻址模式很简单,其实就是找到自己的 IP:PORT 组合信息,然后格式化为⼀个节点信息, 调用 afterLookup 然后将信息存储到 ServerMemberManager 中。

public class StandaloneMemberLookup extends AbstractMemberLookup {
    
    @Override
    public void doStart() {
        String url = InetUtils.getSelfIP() + ":" + EnvUtil.getPort();
        afterLookup(MemberUtil.readServerConf(Collections.singletonList(url)));
    }
    
    @Override
    public boolean useAddressServer() {
        return false;
    }
}
4.2文件寻址

文件寻址模式是 Nacos 集群模式下的默认寻址实现。文件寻址模式很简单,其实就是每个 Nacos 节点需要维护⼀个叫做 cluster.conf 的文件。

192.168.16.101:8847 
192.168.16.102 
192.168.16.103

该文件默认只需要填写每个成员节点的 IP 信息即可,端口会自动选择 Nacos 的默认端口 8848, 如过说有特殊需求更改了 Nacos 的端口信息,则需要在该文件将该节点的完整网路地址信息补充 完整(IP:PORT)。

当 Nacos 节点启动时,会读取该文件的内容,然后将文件内的 IP 解析为节点列表,调用 afterLookup 存入 ServerMemberManager 。

但是,这种默认寻址模式有⼀个缺点——运维成本较大,可以想象下,当你新增⼀个 Nacos 节点时, 需要去手动修改每个 Nacos 节点下的 cluster.conf 文件,这是多么辛苦的⼀件工作,或者稍微高 端⼀点,利用 ansible 等自动化部署的工具去推送 cluster.conf 文件去代替自己的手动操作,虽然说省去了较为繁琐的人工操作步骤,但是仍旧存在⼀个问题——每⼀个 Nacos 节点都存在⼀份 cluster.conf 文件,如果其中⼀个节点的 cluster.conf 文件修改失败,就造成了集群间成员节点列 表数据的不⼀致性,因此,又引申出了新的寻址模式——地址服务器寻址模式。

public class FileConfigMemberLookup extends AbstractMemberLookup {
    
    private static final String DEFAULT_SEARCH_SEQ = "cluster.conf";
    
    private FileWatcher watcher = new FileWatcher() {
        @Override
        public void onChange(FileChangeEvent event) {
            readClusterConfFromDisk();
        }
        
        @Override
        public boolean interest(String context) {
            return StringUtils.contains(context, DEFAULT_SEARCH_SEQ);
        }
    };
    
    @Override
    public void doStart() throws NacosException {
        readClusterConfFromDisk();
        
        // Use the inotify mechanism to monitor file changes and automatically
        // trigger the reading of cluster.conf
        try {
            WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), watcher);
        } catch (Throwable e) {
            Loggers.CLUSTER.error("An exception occurred in the launch file monitor : {}", e.getMessage());
        }
    }
    
    @Override
    public boolean useAddressServer() {
        return false;
    }
    
    @Override
    public void destroy() throws NacosException {
        WatchFileCenter.deregisterWatcher(EnvUtil.getConfPath(), watcher);
    }
    
    private void readClusterConfFromDisk() {
        Collection tmpMembers = new ArrayList<>();
        try {
            List tmp = EnvUtil.readClusterConf();
            tmpMembers = MemberUtil.readServerConf(tmp);
        } catch (Throwable e) {
            Loggers.CLUSTER
                    .error("nacos-XXXX [serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());
        }
        
        afterLookup(tmpMembers);
    }
}

如果发现集群扩缩容,那么就需要修改每个 Nacos 节点下的 cluster.conf 文件,然后 Nacos 内 部的文件变动监听中心会自动发现文件修改,重新读取文件内容、加载 IP 列表信息、更新新增的 节点。

	private FileWatcher watcher = new FileWatcher() {
        @Override
        public void onChange(FileChangeEvent event) {
            readClusterConfFromDisk();
        }
        
        @Override
        public boolean interest(String context) {
            return StringUtils.contains(context, DEFAULT_SEARCH_SEQ);
        }
    };
4.3地址服务器寻址

地址服务器寻址模式是 Nacos 官方推荐的⼀种集群成员节点信息管理,该模式利用了⼀个简易的 web 服务器,用于管理 cluster.conf 文件的内容信息,这样,运维人员只需要管理这⼀份集群成员 节点内容即可,而每个 Nacos 成员节点,只需要向这个 web 节点定时请求当前最新的集群成员节 点列表信息即可。
因此,通过地址服务器这种模式,大大简化了 Nacos 集群节点管理的成本,同时,地址服务器是 ⼀个非常简单的 web 程序,其程序的稳定性能够得到很好的保障。

public class AddressServerMemberLookup extends AbstractMemberLookup {
    
    private final GenericType genericType = new GenericType() { };
    
    public String domainName;
    
    public String addressPort;
    
    public String addressUrl;
    
    public String envIdUrl;
    
    public String addressServerUrl;
    
    private volatile boolean isAddressServerHealth = true;
    
    private int addressServerFailCount = 0;
    
    private int maxFailCount = 12;
    
    private final NacosRestTemplate restTemplate = HttpClientBeanHolder.getNacosRestTemplate(Loggers.CORE);
    
    private volatile boolean shutdown = false;
    
    private static final String HEALTH_CHECK_FAIL_COUNT_PROPERTY = "maxHealthCheckFailCount";
    
    private static final String DEFAULT_HEALTH_CHECK_FAIL_COUNT = "12";
    
    private static final String DEFAULT_SERVER_DOMAIN = "jmenv.tbsite.net";
    
    private static final String DEFAULT_SERVER_POINT = "8080";
    
    private static final int DEFAULT_SERVER_RETRY_TIME = 5;
    
    private static final long DEFAULT_SYNC_TASK_DELAY_MS = 5_000L;
    
    private static final String ADDRESS_SERVER_DOMAIN_ENV = "address_server_domain";
    
    private static final String ADDRESS_SERVER_DOMAIN_PROPERTY = "address.server.domain";
    
    private static final String ADDRESS_SERVER_PORT_ENV = "address_server_port";
    
    private static final String ADDRESS_SERVER_PORT_PROPERTY = "address.server.port";
    
    private static final String ADDRESS_SERVER_URL_ENV = "address_server_url";
    
    private static final String ADDRESS_SERVER_URL_PROPERTY = "address.server.url";
    
    private static final String ADDRESS_SERVER_RETRY_PROPERTY = "nacos.core.address-server.retry";
    
    @Override
    public void doStart() throws NacosException {
        this.maxFailCount = Integer.parseInt(EnvUtil.getProperty(HEALTH_CHECK_FAIL_COUNT_PROPERTY, DEFAULT_HEALTH_CHECK_FAIL_COUNT));
        initAddressSys();
        run();
    }
    
    @Override
    public boolean useAddressServer() {
        return true;
    }
    
    private void initAddressSys() {
        String envDomainName = System.getenv(ADDRESS_SERVER_DOMAIN_ENV);
        if (StringUtils.isBlank(envDomainName)) {
            domainName = EnvUtil.getProperty(ADDRESS_SERVER_DOMAIN_PROPERTY, DEFAULT_SERVER_DOMAIN);
        } else {
            domainName = envDomainName;
        }
        String envAddressPort = System.getenv(ADDRESS_SERVER_PORT_ENV);
        if (StringUtils.isBlank(envAddressPort)) {
            addressPort = EnvUtil.getProperty(ADDRESS_SERVER_PORT_PROPERTY, DEFAULT_SERVER_POINT);
        } else {
            addressPort = envAddressPort;
        }
        String envAddressUrl = System.getenv(ADDRESS_SERVER_URL_ENV);
        if (StringUtils.isBlank(envAddressUrl)) {
            addressUrl = EnvUtil.getProperty(ADDRESS_SERVER_URL_PROPERTY, EnvUtil.getContextPath() + "/" + "serverlist");
        } else {
            addressUrl = envAddressUrl;
        }
        addressServerUrl = "http://" + domainName + ":" + addressPort + addressUrl;
        envIdUrl = "http://" + domainName + ":" + addressPort + "/env";
        
        Loggers.CORE.info("ServerListService address-server port:" + addressPort);
        Loggers.CORE.info("ADDRESS_SERVER_URL:" + addressServerUrl);
    }
    
    @SuppressWarnings("PMD.UndefineMagicConstantRule")
    private void run() throws NacosException {
        // With the address server, you need to perform a synchronous member node pull at startup
        // Repeat three times, successfully jump out
        boolean success = false;
        Throwable ex = null;
        int maxRetry = EnvUtil.getProperty(ADDRESS_SERVER_RETRY_PROPERTY, Integer.class, DEFAULT_SERVER_RETRY_TIME);
        for (int i = 0; i < maxRetry; i++) {
            try {
                syncFromAddressUrl();
                success = true;
                break;
            } catch (Throwable e) {
                ex = e;
                Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
            }
        }
        if (!success) {
            throw new NacosException(NacosException.SERVER_ERROR, ex);
        }
        
        GlobalExecutor.scheduleByCommon(new AddressServerSyncTask(), DEFAULT_SYNC_TASK_DELAY_MS);
    }
    
    @Override
    public void destroy() throws NacosException {
        shutdown = true;
    }
    
    @Override
    public Map info() {
        Map info = new HashMap<>(4);
        info.put("addressServerHealth", isAddressServerHealth);
        info.put("addressServerUrl", addressServerUrl);
        info.put("envIdUrl", envIdUrl);
        info.put("addressServerFailCount", addressServerFailCount);
        return info;
    }
    
    private void syncFromAddressUrl() throws Exception {
        RestResult result = restTemplate
                .get(addressServerUrl, Header.EMPTY, Query.EMPTY, genericType.getType());
        if (result.ok()) {
            isAddressServerHealth = true;
            Reader reader = new StringReader(result.getData());
            try {
                afterLookup(MemberUtil.readServerConf(EnvUtil.analyzeClusterConf(reader)));
            } catch (Throwable e) {
                Loggers.CLUSTER.error("[serverlist] exception for analyzeClusterConf, error : {}",
                        ExceptionUtil.getAllExceptionMsg(e));
            }
            addressServerFailCount = 0;
        } else {
            addressServerFailCount++;
            if (addressServerFailCount >= maxFailCount) {
                isAddressServerHealth = false;
            }
            Loggers.CLUSTER.error("[serverlist] failed to get serverlist, error code {}", result.getCode());
        }
    }
    
    class AddressServerSyncTask implements Runnable {
        
        @Override
        public void run() {
            if (shutdown) {
                return;
            }
            try {
                syncFromAddressUrl();
            } catch (Throwable ex) {
                addressServerFailCount++;
                if (addressServerFailCount >= maxFailCount) {
                    isAddressServerHealth = false;
                }
                Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
            } finally {
                GlobalExecutor.scheduleByCommon(this, DEFAULT_SYNC_TASK_DELAY_MS);
            }
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/681955.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号