欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Nacos服務注冊與發(fā)現(xiàn)原理解讀

 更新時間:2025年08月28日 14:05:46   作者:shangjg3  
Nacos是阿里巴巴開源的微服務組件,支持服務注冊、發(fā)現(xiàn)及配置管理,采用客戶端心跳維護、服務端推送與長輪詢同步,結合健康檢查機制,實現(xiàn)高效可靠的微服務治理

Nacos是阿里巴巴開源的服務注冊與發(fā)現(xiàn)組件,同時也提供配置管理功能。它支持基于DNS和RPC的服務發(fā)現(xiàn),致力于幫助開發(fā)人員發(fā)現(xiàn)、配置和管理微服務。

下面將深入解析其服務注冊與發(fā)現(xiàn)的核心原理,并提供關鍵源碼示例。

核心原理架構

Nacos的服務注冊與發(fā)現(xiàn)架構主要包含三個核心組件:

  • 服務提供者:負責將自身服務實例注冊到Nacos Server
  • 服務消費者:負責從Nacos Server獲取服務列表并進行服務調(diào)用
  • Nacos Server:負責維護服務實例信息,處理注冊、發(fā)現(xiàn)、健康檢查等請求

服務注冊原理

服務注冊是指服務提供者將自身服務實例的信息注冊到Nacos Server的過程。

其核心流程如下:

  • 1. 服務實例啟動時,通過SDK向Nacos Server發(fā)送注冊請求
  • 2. Nacos Server接收請求并驗證信息,將服務實例信息存儲到內(nèi)存和持久化存儲中
  • 3. 服務實例定期向Nacos Server發(fā)送心跳包維持注冊狀態(tài)

服務注冊核心源碼

下面是Nacos服務注冊的核心源碼示例:

// ServiceRegistration接口定義服務注冊的基本方法
public interface ServiceRegistration<T> {
    void register();
    void deregister();
    T getRegistration();
}

// NacosServiceRegistry實現(xiàn)了服務注冊邏輯
@Service
public class NacosServiceRegistry implements ServiceRegistry<NacosRegistration> {
    
    private final NacosServiceManager nacosServiceManager;
    private final NacosRegistrationProperties registrationProperties;
    
    public NacosServiceRegistry(NacosServiceManager nacosServiceManager,
                               NacosRegistrationProperties registrationProperties) {
        this.nacosServiceManager = nacosServiceManager;
        this.registrationProperties = registrationProperties;
    }
    
    @Override
    public void register(NacosRegistration registration) {
        if (StringUtils.isEmpty(registration.getServiceId())) {
            log.warn("No service to register for nacos client...");
            return;
        }
        
        // 構建服務實例注冊信息
        Instance instance = getNacosInstanceFromRegistration(registration);
        
        try {
            // 調(diào)用Nacos客戶端進行服務注冊
            namingService().registerInstance(
                registration.getServiceId(), 
                registration.getGroupName(), 
                instance);
            log.info("nacos registry, {} {}:{} register finished",
                registration.getServiceId(),
                instance.getIp(), instance.getPort());
        } catch (Exception e) {
            log.error("nacos registry error", e);
        }
    }
    
    // 獲取Nacos命名服務客戶端
    private NamingService namingService() throws NacosException {
        return nacosServiceManager.getNamingService(registrationProperties);
    }
    
    // 從注冊信息構建Nacos實例對象
    private Instance getNacosInstanceFromRegistration(NacosRegistration registration) {
        Instance instance = new Instance();
        // 設置實例基本信息
        instance.setIp(registration.getIp());
        instance.setPort(registration.getPort());
        instance.setWeight(registration.getWeight() == null ? 1.0F : registration.getWeight());
        instance.setClusterName(registration.getClusterName());
        instance.setHealthy(registration.isHealthy());
        instance.setServiceName(registration.getServiceId());
        instance.setInstanceId(registration.getInstanceId());
        instance.setEphemeral(registration.isEphemeral());
        
        // 設置元數(shù)據(jù)
        if (registration.getMetadata() != null) {
            instance.setMetadata(registration.getMetadata());
        }
        
        return instance;
    }
}

// NacosNamingService是Nacos命名服務的核心實現(xiàn)類
public class NacosNamingService implements NamingService {
    
    private final NacosServiceFactory serviceFactory;
    private final NamingProxy namingProxy;
    private final ClientWorker clientWorker;
    
    public NacosNamingService(Properties properties) throws NacosException {
        // 初始化相關組件
        this.serviceFactory = new NacosServiceFactory(properties);
        this.namingProxy = serviceFactory.createNamingProxy();
        this.clientWorker = new ClientWorker(namingProxy, properties);
    }
    
    @Override
    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
        // 檢查服務名是否合法
        if (StringUtils.isEmpty(groupName)) {
            groupName = Constants.DEFAULT_GROUP;
        }
        
        // 調(diào)用客戶端工作類處理注冊
        clientWorker.registerInstance(serviceName, groupName, instance);
    }
    
    // 客戶端工作類處理注冊邏輯
    public class ClientWorker {
        private final NamingProxy namingProxy;
        private final ServiceInfoHolder serviceInfoHolder;
        private final ScheduledExecutorService executorService;
        
        public ClientWorker(NamingProxy namingProxy, Properties properties) {
            this.namingProxy = namingProxy;
            this.serviceInfoHolder = new ServiceInfoHolder();
            this.executorService = Executors.newScheduledThreadPool(1, 
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setName("com.alibaba.nacos.naming.client.Worker");
                        t.setDaemon(true);
                        return t;
                    }
                });
            
            // 啟動心跳任務
            scheduleHeartbeat();
        }
        
        public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
            // 構建注冊請求參數(shù)
            Map<String, String> params = new HashMap<>(16);
            params.put("serviceName", serviceName);
            params.put("groupName", groupName);
            params.put("ip", instance.getIp());
            params.put("port", String.valueOf(instance.getPort()));
            params.put("weight", String.valueOf(instance.getWeight()));
            params.put("clusterName", instance.getClusterName());
            params.put("ephemeral", String.valueOf(instance.isEphemeral()));
            params.put("serviceId", instance.getServiceId());
            params.put("metadata", JSON.toJSONString(instance.getMetadata()));
            
            // 發(fā)送注冊請求到Nacos Server
            namingProxy.registerInstance(params);
            
            // 加入到服務信息持有者中
            serviceInfoHolder.processServiceJson(
                serviceName, groupName, 
                JSON.toJSONString(Collections.singletonList(instance))
            );
        }
        
        // 啟動心跳任務,定期發(fā)送心跳維持注冊狀態(tài)
        private void scheduleHeartbeat() {
            executorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 發(fā)送心跳包
                        clientWorker.sendHeartbeat();
                    } catch (Exception e) {
                        log.error("Exception when sending heartbeat", e);
                    }
                }
            }, 5000, 5000, TimeUnit.MILLISECONDS);
        }
        
        // 發(fā)送心跳方法
        public void sendHeartbeat() throws NacosException {
            for (Map.Entry<String, List<Instance>> entry : serviceInfoHolder.getServices().entrySet()) {
                String serviceName = entry.getKey();
                List<Instance> instances = entry.getValue();
                
                for (Instance instance : instances) {
                    if (!instance.isHealthy() || !instance.isEphemeral()) {
                        continue;
                    }
                    
                    // 構建心跳請求參數(shù)
                    Map<String, String> params = new HashMap<>(16);
                    params.put("serviceName", serviceName);
                    params.put("ip", instance.getIp());
                    params.put("port", String.valueOf(instance.getPort()));
                    params.put("clusterName", instance.getClusterName());
                    params.put("serviceId", instance.getServiceId());
                    
                    // 發(fā)送心跳請求
                    namingProxy.sendHeartbeat(params);
                }
            }
        }
    }
}

服務發(fā)現(xiàn)原理

服務發(fā)現(xiàn)是指服務消費者從Nacos Server獲取服務列表,并根據(jù)一定的負載均衡策略選擇具體服務實例進行調(diào)用的過程。

核心流程如下:

  • 1. 服務消費者啟動時,向Nacos Server訂閱所需服務
  • 2. Nacos Server推送服務列表給消費者
  • 3. 消費者本地緩存服務列表,并定期更新
  • 4. 服務調(diào)用時,根據(jù)負載均衡策略選擇具體實例

服務發(fā)現(xiàn)核心源碼

下面是Nacos服務發(fā)現(xiàn)的核心源碼示例:

// NacosServiceDiscovery實現(xiàn)了服務發(fā)現(xiàn)邏輯
@Service
public class NacosServiceDiscovery implements ServiceDiscovery<ServiceInstance> {
    
    private final NacosServiceManager nacosServiceManager;
    private final NacosDiscoveryProperties discoveryProperties;
    
    public NacosServiceDiscovery(NacosServiceManager nacosServiceManager,
                               NacosDiscoveryProperties discoveryProperties) {
        this.nacosServiceManager = nacosServiceManager;
        this.discoveryProperties = discoveryProperties;
    }
    
    @Override
    public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
        return getInstances(serviceId, "");
    }
    
    @Override
    public List<ServiceInstance> getInstances(String serviceId, String group) throws NacosException {
        if (StringUtils.isEmpty(serviceId)) {
            throw new NacosException(NacosException.INVALID_PARAM, "serviceId is empty");
        }
        
        if (StringUtils.isEmpty(group)) {
            group = discoveryProperties.getGroup();
        }
        
        // 調(diào)用Nacos命名服務獲取實例列表
        List<Instance> instances = namingService().getInstances(serviceId, group);
        
        // 轉換為標準ServiceInstance格式
        return instances.stream()
            .map(instance -> new NacosServiceInstance(instance, serviceId))
            .collect(Collectors.toList());
    }
    
    @Override
    public List<String> getServices() throws NacosException {
        // 獲取所有服務列表
        return namingService().getServicesOfServer(1000, 0).stream()
            .map(serviceInfo -> serviceInfo.getName())
            .collect(Collectors.toList());
    }
    
    // 獲取Nacos命名服務客戶端
    private NamingService namingService() throws NacosException {
        return nacosServiceManager.getNamingService(discoveryProperties.getNacosProperties());
    }
}

// NacosNamingService中的服務發(fā)現(xiàn)相關方法
public class NacosNamingService implements NamingService {
    
    // 獲取服務實例列表
    @Override
    public List<Instance> getInstances(String serviceName, String groupName, List<String> clusters) 
        throws NacosException {
        if (StringUtils.isEmpty(groupName)) {
            groupName = Constants.DEFAULT_GROUP;
        }
        
        // 調(diào)用客戶端工作類獲取實例
        return clientWorker.getInstances(serviceName, groupName, clusters);
    }
    
    // 客戶端工作類處理服務發(fā)現(xiàn)邏輯
    public class ClientWorker {
        // 服務信息持有者,緩存服務列表
        private final ServiceInfoHolder serviceInfoHolder;
        
        public List<Instance> getInstances(String serviceName, String groupName, List<String> clusters) 
            throws NacosException {
            // 構建服務標識
            String serviceId = ServiceIdBuilder.buildServiceId(groupName, serviceName);
            
            // 從服務信息持有者獲取服務信息
            ServiceInfo serviceInfo = serviceInfoHolder.getServiceInfo(serviceId);
            
            // 如果服務信息為空或已過期,主動拉取
            if (serviceInfo == null || serviceInfo.isExpired()) {
                serviceInfo = refreshServiceInfo(serviceName, groupName, clusters);
            }
            
            // 返回可用實例列表
            return serviceInfo == null ? Collections.emptyList() : serviceInfo.getHosts();
        }
        
        // 刷新服務信息
        public ServiceInfo refreshServiceInfo(String serviceName, String groupName, List<String> clusters) 
            throws NacosException {
            String serviceId = ServiceIdBuilder.buildServiceId(groupName, serviceName);
            
            // 構建請求參數(shù)
            Map<String, String> params = new HashMap<>(16);
            params.put("serviceName", serviceName);
            params.put("groupName", groupName);
            if (clusters != null && !clusters.isEmpty()) {
                params.put("clusters", StringUtils.join(clusters, ","));
            }
            
            // 調(diào)用Nacos Server獲取服務信息
            String result = namingProxy.queryList(serviceId, params);
            
            // 處理服務信息
            return serviceInfoHolder.processServiceJson(serviceId, result);
        }
        
        // 服務信息持有者類,負責緩存和管理服務信息
        public class ServiceInfoHolder {
            // 服務信息緩存
            private final Map<String, ServiceInfo> services = new ConcurrentHashMap<>();
            // 上次更新時間
            private final Map<String, Long> lastRefTime = new ConcurrentHashMap<>();
            
            public ServiceInfo processServiceJson(String serviceId, String json) {
                if (StringUtils.isEmpty(json)) {
                    return null;
                }
                
                ServiceInfo serviceInfo = JSON.parseObject(json, ServiceInfo.class);
                
                if (serviceInfo != null) {
                    // 更新服務信息
                    services.put(serviceId, serviceInfo);
                    lastRefTime.put(serviceId, System.currentTimeMillis());
                    
                    // 注冊監(jiān)聽器,當服務信息變化時通知
                    if (null != listeners.get(serviceId)) {
                        for (EventListener listener : listeners.get(serviceId)) {
                            executorService.execute(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        listener.onEvent(new NamingEvent(serviceId, serviceInfo));
                                    } catch (Exception e) {
                                        log.error("EventListener execute error.", e);
                                    }
                                }
                            });
                        }
                    }
                }
                
                return serviceInfo;
            }
            
            // 獲取服務信息
            public ServiceInfo getServiceInfo(String serviceId) {
                ServiceInfo serviceInfo = services.get(serviceId);
                if (serviceInfo != null) {
                    return serviceInfo;
                }
                
                // 如果服務信息不存在,主動拉取
                try {
                    return refreshServiceInfo(serviceId.split(ServiceIdBuilder.SERVICE_ID_SEPARATOR)[0],
                        serviceId.split(ServiceIdBuilder.SERVICE_ID_SEPARATOR)[1], null);
                } catch (NacosException e) {
                    log.error("getServiceInfo error, serviceId: {}", serviceId, e);
                }
                
                return null;
            }
            
            // 服務信息是否過期
            public boolean isExpired(String serviceId) {
                Long lastRef = lastRefTime.get(serviceId);
                if (lastRef == null) {
                    return true;
                }
                
                // 默認15秒更新一次
                return (System.currentTimeMillis() - lastRef) > 15 * 1000;
            }
        }
    }
}

服務健康檢查機制

Nacos的服務健康檢查是保證服務可用性的關鍵機制,主要包含兩種檢查方式:

1. 客戶端主動上報:服務實例定期向Nacos Server發(fā)送心跳包

2. 服務端主動檢查:Nacos Server定期向服務實例發(fā)送健康檢查請求

健康檢查的核心源碼涉及到ClientWorker類中的心跳機制和Server端的檢查邏輯,上述源碼中已包含客戶端心跳相關部分。

服務配置與同步機制

Nacos采用了長輪詢和推送相結合的方式實現(xiàn)服務配置的實時同步:

1. 客戶端發(fā)起長輪詢請求到服務端

2. 服務端有變更時立即響應,無變更則等待一段時間后響應

3. 客戶端收到響應后立即發(fā)起新的長輪詢請求

4. 服務端也可以主動推送變更到客戶端

這種機制保證了服務信息的實時性和一致性,同時減少了客戶端與服務端的通信開銷。

總結

Nacos的服務注冊與發(fā)現(xiàn)機制通過簡潔而高效的設計,實現(xiàn)了微服務的自動注冊、發(fā)現(xiàn)和健康管理。其核心原理包括:

  • 基于客戶端的服務注冊與心跳維持
  • 基于長輪詢和推送的服務信息同步
  • 靈活的服務發(fā)現(xiàn)與負載均衡策略
  • 可靠的服務健康檢查機制

通過上述源碼可以看到,Nacos通過NamingService接口封裝了核心功能,ClientWorker處理具體的注冊、發(fā)現(xiàn)和心跳邏輯,ServiceInfoHolder負責服務信息的緩存和管理,整體架構清晰且易于擴展。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • jar命令修改jar包中的application.yml配置文件

    jar命令修改jar包中的application.yml配置文件

    本文主要介紹了jar命令修改jar包中的application.yml配置文件,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-08-08
  • java實現(xiàn)通過綁定郵箱找回密碼功能

    java實現(xiàn)通過綁定郵箱找回密碼功能

    這篇文章主要為大家詳細介紹了java實現(xiàn)通過綁定郵箱找回密碼功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-02-02
  • Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案

    Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案

    本文主要介紹了Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • 解決Idea的選擇文件后定位瞄準器"Select Opened File"的功能不見了

    解決Idea的選擇文件后定位瞄準器"Select Opened File"的功能

    使用IntelliJ IDEA時,可能會發(fā)現(xiàn)"SelectOpenedFile"功能不見了,這個功能允許用戶快速定位到當前打開文件的位置,若要找回此功能,只需在IDEA的標題欄上右鍵,然后選擇"Always Select Opened File",這樣就可以重新啟用這個便捷的功能
    2024-11-11
  • Java打亂ArrayList生成一個隨機序列列表

    Java打亂ArrayList生成一個隨機序列列表

    有時候會需要將一個ArrayList或者數(shù)組中的數(shù)字打亂,方便后續(xù)使用,比如隨機出題、答案選項打亂、連線題打亂、抽獎號碼打亂等等,把我自己寫的一段代碼貼出來分享給大家。
    2016-08-08
  • JavaWeb實體類轉為json對象的實現(xiàn)方法

    JavaWeb實體類轉為json對象的實現(xiàn)方法

    這篇文章主要介紹了JavaWeb實體類轉為json對象的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • Java?IO流必備之File、遞歸與字符集舉例詳解

    Java?IO流必備之File、遞歸與字符集舉例詳解

    Java?IO輸入輸出是我們?nèi)粘i_發(fā)中必不可少的一部分,無論是讀寫文件、傳輸數(shù)據(jù)、處理日志,IO?都是底層支持,這篇文章主要介紹了Java?IO流必備之File、遞歸與字符集的相關資料,需要的朋友可以參考下
    2025-06-06
  • java實現(xiàn)雙人五子棋游戲

    java實現(xiàn)雙人五子棋游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)雙人五子棋游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 解決阿里云OSS使用URL無法訪問圖片的兩種方法

    解決阿里云OSS使用URL無法訪問圖片的兩種方法

    這篇文章主要介紹了解決阿里云OSS使用URL無法訪問圖片的兩種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • 基于resty orm的ActiveRecord操作數(shù)據(jù)指南

    基于resty orm的ActiveRecord操作數(shù)據(jù)指南

    這篇文章主要為大家介紹了基于resty orm的ActiveRecord操作數(shù)據(jù)指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2022-03-03

最新評論