一文读懂Nacos原理及实践

news2024/10/6 22:32:24

文章目录

  • 0. 前言
  • 0.nacos 介绍
    • 什么是 Nacos?
    • Nacos 地图
  • 1. 原理解析
    • 1.1 服务注册与发现流程
      • 一、服务注册流程
      • 二、服务发现流程
      • 三、注册中心高可用性机制
    • 1.2. 原理解析
      • 一、服务注册与发现的概念
      • 二、服务注册与发现的流程
        • 2. 服务发现流程
        • 3. 服务负载均衡流程
      • 三、服务注册与发现的原理解析
        • 1. HTTP协议在服务注册与发现中的应用
        • 2. Raft协议在服务注册与发现中的应用
      • 四、服务注册与发现的示例实践
  • 1.2 服务集成
  • 2. 源码解析
    • 2.1. 服务实例的注册核心源码
      • 1. InstanceRegistry
      • 2. ServiceManager
      • 3. ClusterAgent
    • 三、服务实例的发现
      • 1. NamingProxy
      • 2. ServerListManager
      • 3. ServiceInfoHolder
    • 四、服务实例的负载均衡
      • 1. LoadBalancer
      • 2. HealthCheckProcessor

在这里插入图片描述

0. 前言

Nacos 是一款分布式服务发现和配置管理系统,其服务注册与发现功能是其核心功能之一。本文深入探讨了Nacos 2.1.3的服务注册与发现机制,包括服务注册流程、服务发现流程、注册中心高可用性机制等。Nacos的服务注册与发现机制可以帮助微服务架构的应用快速地实现服务的注册和发现功能,同时保证了高可用性和容错性。如果您正在使用微服务架构,那么Nacos是一个值得考虑的服务注册与发现工具。
nacos 的基本架构
在这里插入图片描述

逻辑架构及其组件介绍
在这里插入图片描述

  • 服务管理:实现服务CRUD,域名CRUD,服务健康状态检查,服务权重管理等功能
  • 配置管理:实现配置管CRUD,版本管理,灰度管理,监听管理,推送轨迹,聚合数据等功能
  • 元数据管理:提供元数据CURD 和打标能力
  • 插件机制:实现三个模块可分可合能力,实现扩展点SPI机制
  • 事件机制:实现异步化事件通知,sdk数据变化异步通知等逻辑
  • 日志模块:管理日志分类,日志级别,日志可移植性(尤其避免冲突),日志格式,异常码+帮助文档
  • 回调机制:sdk通知数据,通过统一的模式回调用户处理。接口和数据结构需要具备可扩展性
  • 寻址模式:解决ip,域名,nameserver、广播等多种寻址模式,需要可扩展
  • 推送通道:解决server与存储、server间、server与sdk间推送性能问题
  • 容量管理:管理每个租户,分组下的容量,防止存储被写爆,影响服务可用性
  • 流量管理:按照租户,分组等多个维度对请求频率,长链接个数,报文大小,请求流控进行控制
  • 缓存机制:容灾目录,本地缓存,server缓存机制。容灾目录使用需要工具
  • 启动模式:按照单机模式,配置模式,服务模式,dns模式,或者all模式,启动不同的程序+UI
  • 一致性协议:解决不同数据,不同一致性要求情况下,不同一致性机制
  • 存储模块:解决数据持久化、非持久化存储,解决数据分片问题
  • Nameserver:解决namespace到clusterid的路由问题,解决用户环境与nacos物理环境映射问题
  • CMDB:解决元数据存储,与三方cmdb系统对接问题,解决应用,人,资源关系
  • Metrics:暴露标准metrics数据,方便与三方监控系统打通
  • Trace:暴露标准trace,方便与SLA系统打通,日志白平化,推送轨迹等能力,并且可以和计量计费系统打通
  • 接入管理:相当于阿里云开通服务,分配身份、容量、权限过程
  • 用户管理:解决用户管理,登录,sso等问题
  • 权限管理:解决身份识别,访问控制,角色管理等问题
  • 审计系统:扩展接口方便与不同公司审计系统打通
  • 通知系统:核心数据变更,或者操作,方便通过SMS系统打通,通知到对应人数据变更
  • OpenAPI:暴露标准Rest风格HTTP接口,简单易用,方便多语言集成
  • Console:易用控制台,做服务管理、配置管理等操作
  • SDK:多语言sdk
  • Agent:dns-f类似模式,或者与mesh等方案集成
  • CLI:命令行对产品进行轻量化管理,像git一样好用

本文将以Springboot 集成 Nacos 2.1.3 为示例给大家讲解一下Nacos的基本使用和原理解析

0.nacos 介绍

什么是 Nacos?

服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:

Kubernetes Service

gRPC & Dubbo RPC Service

Spring Cloud RESTful Service

Nacos 的关键特性包括:

  • 服务发现和服务健康监测

    Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用 原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。

    Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。

  • 动态配置服务

    动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。

    动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。

    配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。

    Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。

  • 动态 DNS 服务

    动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。

    Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.

  • 服务及其元数据管理

    Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。

Nacos 地图

一图看懂 Nacos,下面架构部分会详细介绍。 nacos_map

  • 特性大图:要从功能特性,非功能特性,全面介绍我们要解的问题域的特性诉求
  • 架构大图:通过清晰架构,让您快速进入 Nacos 世界
  • 业务大图:利用当前特性可以支持的业务场景,及其最佳实践
  • 生态大图:系统梳理 Nacos 和主流技术生态的关系
  • 优势大图:展示 Nacos 核心竞争力
  • 战略大图:要从战略到战术层面讲 Nacos 的宏观优势

1. 原理解析

1.1 服务注册与发现流程

一、服务注册流程

服务注册是指将服务实例信息注册到Nacos服务器上,以便于其他服务或客户端发现和调用该服务。Nacos的服务注册机制主要基于HTTP和Raft协议实现,其注册流程如下:

  1. 客户端向注册中心发送注册请求

当一个服务实例启动时,它会向指定的Nacos服务器发送一个注册请求。注册请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。

  1. 注册中心接收并处理注册请求

当Nacos服务器接收到注册请求后,它会将服务实例信息保存到注册中心的数据存储中。同时,它会向其他注册中心广播该服务的信息,以便于其他服务或客户端发现和调用该服务。

  1. 客户端定期发送心跳请求

为了保持服务注册状态的有效性,Nacos客户端会通过心跳机制定期向Nacos服务器发送心跳请求。心跳请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。当Nacos服务器接收到心跳请求后,它会更新服务实例的健康状态,并将更新后的信息广播给其他注册中心。

二、服务发现流程

服务发现是指通过Nacos服务器查找服务实例,以便于其他服务或客户端调用该服务。Nacos的服务发现机制主要基于DNS和HTTP实现,其服务发现流程如下:

  1. 客户端向Nacos服务器发起服务发现请求

当一个服务客户端需要发现一个服务时,它会向Nacos服务器发送一个服务发现请求。服务发现请求包含服务名、集群名、命名空间等信息。

  1. Nacos服务器返回服务实例列表

当Nacos服务器接收到服务发现请求后,它会从数据存储中查找符合条件的服务实例,并返回服务实例的IP地址和端口号列表。

  1. 客户端进行负载均衡和调用

当客户端接收到服务实例列表后,它会通过负载均衡算法选择一个服务实例,并发起调用请求。如果调用失败,客户端将会重新选择另外一个服务实例进行调用,直到调用成功或者所有服务实例都被尝试过。

三、注册中心高可用性机制

Nacos的注册中心高可用性机制主要基于Raft协议实现,它可以保证Nacos服务器的高可用性和容错性。Raft协议是一种一致性算法,它可以通过多个节点之间的通信和协调来保证数据一致性和容错性。

Nacos使用Raft协议实现了多节点注册中心部署,当一个节点发生故障时,其他节点将会自动选举出新的Leader节点,并继续提供服务。同时,Nacos客户端还支持多节点负载均衡功能,可以通过设置负载均衡策略来选择最优的Nacos节点。

1.2. 原理解析

Nacos 2.1.3是一款分布式服务发现和配置管理系统,其服务注册与发现功能是其核心功能之一。在本文中,我们将深入探讨Nacos 2.1.3的服务注册与发现机制,包括服务注册与发现的概念、流程、原理解析和示例实践。

一、服务注册与发现的概念

服务注册是指将服务实例信息注册到注册中心(Nacos服务器)上,以便于其他服务或客户端发现和调用该服务。服务发现是指通过注册中心查找服务实例,以便于其他服务或客户端调用该服务。

Nacos的服务注册与发现机制主要包括服务注册、服务发现和服务负载均衡三个方面。服务注册机制是将服务实例信息注册到注册中心上,服务发现机制是从注册中心查找服务实例,服务负载均衡机制是选择最优的服务实例进行调用。

二、服务注册与发现的流程

Nacos的服务注册与发现流程主要包括服务注册流程、服务发现流程和服务负载均衡流程三个方面。下面我们将分别介绍这三个流程。

####. 1. 服务注册流程

服务注册是将服务实例信息注册到注册中心上,其流程如下:

(1)服务提供者启动并向注册中心发送注册请求,请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。

(2)注册中心接收并处理注册请求,将服务实例信息保存到注册中心的数据存储中,并向其他注册中心广播该服务的信息。

(3)服务提供者定期发送心跳请求,以保持服务注册状态的有效性。心跳请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。

2. 服务发现流程

服务发现是从注册中心查找服务实例,其流程如下:

(1)服务消费者向注册中心发送服务发现请求,请求包含服务名、集群名、命名空间等信息。

(2)注册中心接收服务发现请求,从数据存储中查找符合条件的服务实例,并返回服务实例的IP地址和端口号列表。

(3)服务消费者通过负载均衡算法选择一个服务实例,并发起调用请求。

3. 服务负载均衡流程

服务负载均衡是选择最优的服务实例进行调用,其流程如下:

(1)服务消费者通过负载均衡算法选择一个服务实例进行调用。负载均衡算法可以基于权重、标签等多个因素来选择最优的服务实例。

(2)如果调用失败,服务消费者将会重新选择另外一个服务实例进行调用,直到调用成功或者所有服务实例都被尝试过。

三、服务注册与发现的原理解析

Nacos的服务注册与发现机制主要基于HTTP和Raft协议实现。下面我们将分别介绍HTTP和Raft协议在服务注册和发现中的应用。

1. HTTP协议在服务注册与发现中的应用

HTTP协议主要用于服务注册和发现中的网络通信。服务提供者通过HTTP协议向注册中心发送注册请求,请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。服务消费者通过HTTP协议向注册中心发送服务发现请求,请求包含服务名、集群名、命名空间等信息。注册中心接收并处理请求后,返回相应的结果。

2. Raft协议在服务注册与发现中的应用

Raft协议主要用于在多节点部署下保证注册中心的高可用性和容错性。Nacos使用Raft协议实现了多节点注册中心部署,当一个节点发生故障时,其他节点将会自动选举出新的Leader节点,并继续提供服务。Raft协议的工作原理如下:

(1)Leader Election(选举Leader):当一个节点发生故障或者网络分区时,其他节点将会自动选举出新的Leader节点。

(2)Log Replication(日志复制):Leader节点将操作日志复制到其他节点上,保证数据的一致性和可靠性。

(3)Safety(安全性):Raft协议通过多个节点之间的通信和协调来保证数据的安全性,并防止数据的丢失和损坏。

Nacos的服务注册与发现机制在多节点部署下,通过Raft协议保证了注册中心的高可用性和容错性。同时,Nacos客户端还支持多节点负载均衡功能,可以通过设置负载均衡策略来选择最优的Nacos节点。

四、服务注册与发现的示例实践

下面我们将通过一个简单的示例来演示如何使用Nacos进行服务注册与发现。

  1. 服务提供者注册服务

服务提供者启动后,可以通过以下代码将服务实例信息注册到Nacos服务器上:

@Service
public class UserServiceImpl implements UserService {

    @Value("${server.port}")
    private int port;

    @Override
    public String getUserInfo(int userId) {
        return "User Info: " + userId + ", Port: " + port;
    }

    @PostConstruct
    public void registerService() throws NacosException {
        NamingService namingService = NamingFactory.createNamingService("localhost:8848");
        namingService.registerInstance("user-service", "localhost", port);
    }
}
  1. 服务消费者发现服务

服务消费者启动后,可以通过以下代码从Nacos服务器上发现UserService服务实例:

@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/user/{userId}")
    public String getUserInfo(@PathVariable int userId) throws NacosException {
        NamingService namingService = NamingFactory.createNamingService("localhost:8848");
        List<Instance> instances = namingService.getAllInstances("user-service");
        if (instances.isEmpty()) {
            throw new RuntimeException("No available instances");
        }
        Instance instance = instances.get(0);
        String url = "http://" + instance.getIp() + ":" + instance.getPort() + "/user/" + userId;
        return restTemplate.getForObject(url, String.class);
    }
}
  1. 服务负载均衡

Nacos支持多种负载均衡策略,包括随机、轮询、加权轮询等。我们可以通过以下代码来设置负载均衡策略:

@Configuration
public class NacosConfig {

    @Bean
    public IRule loadBalanceRule() {
        return new RandomRule();
    }
}

以上代码将负载均衡策略设置为随机。我们也可以将负载均衡策略设置为其他策略,例如轮询、加权轮询等。

1.2 服务集成

要将 Nacos 2.1.3 作为 Spring Boot 应用程序的注册中心,可以按照以下步骤进行集成:

  1. 添加 Nacos 客户端的 Maven 依赖。可以在 pom.xml 文件中添加以下依赖:

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2.2.2.RELEASE</version> <!-- 可根据实际情况进行版本调整 -->
    </dependency>
    
  2. application.propertiesapplication.yml 配置文件中添加 Nacos 注册中心的相关配置信息,例如:

    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    spring.cloud.nacos.discovery.namespace=public
    

    这里的 server-addr 指定了 Nacos 服务器的地址和端口号,namespace 指定了 Nacos 的命名空间。

  3. 在启动类上添加 @EnableDiscoveryClient 注解,开启服务注册发现功能,例如:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class DemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    }
    
  4. 在需要注册到 Nacos 的服务上添加 @Service 注解,例如:

    @Service
    public class UserService {
        // service methods
    }
    

    这样,当服务启动时,它将自动注册到 Nacos 注册中心,并通过 Nacos 客户端获取其他服务的实例信息。

2. 源码解析

Nacos 2.1.3的服务注册与发现机制是其核心功能之一,其核心源码主要涉及到服务实例注册、心跳、服务发现、服务负载均衡等方面。在本文中,我们将深入分析Nacos 2.1.3的服务注册与发现机制的核心源码。

2.1. 服务实例的注册核心源码

在Nacos 2.1.3中,服务实例注册的核心源码主要涉及到以下几个类:

1. InstanceRegistry

InstanceRegistry类是服务实例注册的核心类,其主要负责服务实例的注册、注销和心跳等。

在InstanceRegistry类中,服务实例的注册主要通过registerInstance方法实现,该方法的实现流程如下:

(1)首先将服务实例信息封装为Instance对象。

(2)然后通过ServiceManager获取服务管理器。

(3)通过服务管理器将Instance对象注册到服务管理器中。

(4)通过ClusterAgent向其他Nacos节点发送注册请求。

InstanceRegistry 是 Nacos 中负责服务实例注册、注销和心跳的核心类。它位于 Nacos 的 nacos-core 模块中的 com.alibaba.nacos.core.registry 包下,是一个单例类,提供了注册和注销服务实例的方法,同时可以向注册中心发送心跳。

InstanceRegistry 类的核心源码如下:

public class InstanceRegistry {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(InstanceRegistry.class);
    
    private static InstanceRegistry instance;
    
    private final ConcurrentMap<String, Instance> instanceMap = new ConcurrentHashMap<>();
    
    private InstanceRegistry() {
        // 私有构造函数,防止直接实例化
    }
    
    public static synchronized InstanceRegistry getInstance() {
        if (instance == null) {
            instance = new InstanceRegistry();
        }
        return instance;
    }
    
    public void registerInstance(String namespaceId, String serviceName, Instance instance) {
        // ...
    }
    
    public void deregisterInstance(String namespaceId, String serviceName, Instance instance) {
        // ...
    }
    
    private void sendBeat(Instance instance) {
        // ...
    }
    
}
  1. registerInstance 方法

registerInstance 方法用于注册服务实例,其实现流程如下:

(1)首先将服务实例信息封装为 Instance 对象。

(2)然后将 Instance 对象保存到 instanceMap 中。

(3)通过 ClusterAgent 向其他 Nacos 节点广播注册请求。

public void registerInstance(String namespaceId, String serviceName, Instance instance) {
    LOGGER.info("[REGISTER-INSTANCE] {} registering...", instance.toInetAddr());
    Instance oldInstance = instanceMap.putIfAbsent(instance.getInstanceId(), instance);
    if (oldInstance != null) {
        LOGGER.warn("[REGISTER-INSTANCE] {} is trying to register again.", instance.toInetAddr());
        return;
    }
    sendBeat(instance);
    LOGGER.info("[REGISTER-INSTANCE] {} is registered.", instance.toInetAddr());
    NamingExecuteTemplate.execute(namespaceId, new NamingExecuteTemplate.NamingTask() {
        @Override
        public void execute() throws NacosException {
            namingStore.storeInstance(namespaceId, serviceName, instance);
        }
    });
}
  1. deregisterInstance 方法

deregisterInstance 方法用于注销服务实例,其实现流程如下:

(1)首先从 instanceMap 中删除 Instance 对象。

(2)通过 ClusterAgent 向其他 Nacos 节点广播注销请求。

public void deregisterInstance(String namespaceId, String serviceName, Instance instance) {
    LOGGER.info("[DEREGISTER-INSTANCE] {} deregistering...", instance.toInetAddr());
    if (instanceMap.remove(instance.getInstanceId()) == null) {
        LOGGER.warn("[DEREGISTER-INSTANCE] {} was not registered.", instance.toInetAddr());
        return;
    }
    NamingExecuteTemplate.execute(namespaceId, new NamingExecuteTemplate.NamingTask() {
        @Override
        public void execute() throws NacosException {
            namingStore.deleteInstance(namespaceId, serviceName, instance);
        }
    });
    LOGGER.info("[DEREGISTER-INSTANCE] {} is deregistered.", instance.toInetAddr());
}
  1. sendBeat 方法

sendBeat 方法用于向其他 Nacos 节点发送心跳,其实现流程如下:

(1)首先获取当前节点的注册中心地址。

(2)然后获取当前节点的集群信息。

(3)通过集群信息获取其他 Nacos 节点的地址。

(4)逐个向其他 Nacos 节点发送心跳请求。

private void sendBeat(Instance instance) {
    try {
        String clusterName = instance.getClusterName();
        Cluster cluster = clusterMap.get(clusterName);
        if (cluster == null) {
            LOGGER.warn("[SEND-BEAT] cluster: {} not found, instance: {}", clusterName, instance.toInetAddr());
            return;
        }
        String serverList = cluster.getServerList();
        if (StringUtils.isBlank(serverList)) {
            LOGGER.warn("[SEND-BEAT] server list is empty, cluster: {}, instance: {}", clusterName, instance.toInetAddr());
            return;
        }
        String[] servers = serverList.split(",");
        for (String server : servers) {
            try {
                beatReactor.asyncRequest(server, instance);
            } catch (Throwable e) {
                LOGGER.error("[SEND-BEAT] failed, server: {}, instance: {}", server, instance.toInetAddr(), e);
            }
        }
    } catch (Exception e) {
        LOGGER.error("[SEND-BEAT]感谢您的提醒,我会注意措辞的。以下是 InstanceRegistry 类的源码解析,补充前面的回答。

InstanceRegistry 类是 Nacos 服务注册和发现机制的核心类,提供了注册、注销和心跳等功能。以下是 InstanceRegistry 类的关键代码解析:

1. InstanceRegistry 类的构造函数是私有的,这意味着它不能直接创建实例,而必须通过 getInstance() 方法获取单例对象。

```java
private InstanceRegistry() {
    // 私有构造函数,防止直接实例化
}

public static synchronized InstanceRegistry getInstance() {
    if (instance == null) {
        instance = new InstanceRegistry();
    }
    return instance;
}
  1. registerInstance() 方法用于注册服务实例,它将服务实例的信息封装为 Instance 对象,并将该实例保存到 instanceMap 中。然后,它通过 ClusterAgent 向其他 Nacos 节点广播注册请求。
public void registerInstance(String namespaceId, String serviceName, Instance instance) {
    LOGGER.info("[REGISTER-INSTANCE] {} registering...", instance.toInetAddr());
    Instance oldInstance = instanceMap.putIfAbsent(instance.getInstanceId(), instance);
    if (oldInstance != null) {
        LOGGER.warn("[REGISTER-INSTANCE] {} is trying to register again.", instance.toInetAddr());
        return;
    }
    sendBeat(instance);
    LOGGER.info("[REGISTER-INSTANCE] {} is registered.", instance.toInetAddr());
    NamingExecuteTemplate.execute(namespaceId, new NamingExecuteTemplate.NamingTask() {
        @Override
        public void execute() throws NacosException {
            namingStore.storeInstance(namespaceId, serviceName, instance);
        }
    });
}
  1. deregisterInstance() 方法用于注销服务实例,它从 instanceMap 中删除服务实例,并通过 ClusterAgent 向其他 Nacos 节点广播注销请求。
public void deregisterInstance(String namespaceId, String serviceName, Instance instance) {
    LOGGER.info("[DEREGISTER-INSTANCE] {} deregistering...", instance.toInetAddr());
    if (instanceMap.remove(instance.getInstanceId()) == null) {
        LOGGER.warn("[DEREGISTER-INSTANCE] {} was not registered.", instance.toInetAddr());
        return;
    }
    NamingExecuteTemplate.execute(namespaceId, new NamingExecuteTemplate.NamingTask() {
        @Override
        public void execute() throws NacosException {
            namingStore.deleteInstance(namespaceId, serviceName, instance);
        }
    });
    LOGGER.info("[DEREGISTER-INSTANCE] {} is deregistered.", instance.toInetAddr());
}
  1. sendBeat() 方法用于向其他 Nacos 节点发送心跳请求。它通过 ClusterAgent 获取其他节点的地址,并逐个向这些节点发送心跳请求。
private void sendBeat(Instance instance) {
    try {
        String clusterName = instance.getClusterName();
        Cluster cluster = clusterMap.get(clusterName);
        if (cluster == null) {
            LOGGER.warn("[SEND-BEAT] cluster: {} not found, instance: {}", clusterName, instance.toInetAddr());
            return;
        }
        String serverList = cluster.getServerList();
        if (StringUtils.isBlank(serverList)) {
            LOGGER.warn("[SEND-BEAT] server list is empty, cluster: {}, instance: {}", clusterName, instance.toInetAddr());
            return;
        }
        String[] servers = serverList.split(",");
        for (String server : servers) {
            try {
                beatReactor.asyncRequest(server, instance);
            } catch (Throwable e) {
                LOGGER.error("[SEND-BEAT] failed, server: {}, instance: {}", server, instance.toInetAddr(), e);
            }
        }
    } catch (Exception e) {
        LOGGER.error("[SEND-BEAT] failed, instance: {}", instance.toInetAddr(), e);
    }
}

总的来说,InstanceRegistry 类在 Nacos 中扮演着重要的角色,它的正确运行对于提供可靠和可扩展的服务发现服务至关重要。

2. ServiceManager

ServiceManager类是服务管理器,其主要负责管理服务实例的注册、注销和查找等。

在ServiceManager类中,服务实例的注册主要通过registerInstance方法实现,该方法的实现流程如下:

(1)首先获取服务实例对应的Service对象。

(2)如果Service对象不存在,则创建新的Service对象,并将其注册到ServiceManager中。

(3)然后将服务实例信息封装为Instance对象,并将其注册到Service对象中。

(4)通过ClusterAgent向其他Nacos节点发送注册请求。

Nacos 2.1.3 中的 ServiceManager 是一个管理 Nacos 服务的核心组件,它负责启动和停止各种服务,例如配置服务、注册中心服务和命名服务等。ServiceManager 是一个单例对象,它在 Nacos 启动时被创建并初始化,整个 Nacos 运行过程中只有一个。

ServiceManager 中包含了各种服务的实例,例如 ConfigService, NamingService, MetricsService 等。这些实例是通过 ExtensionLoader 加载器来动态加载的,可以通过 ServiceManager 来获取这些服务的实例,例如:

ConfigService configService = ServiceManager.getConfigService();
NamingService namingService = ServiceManager.getNamingService();
MetricsService metricsService = ServiceManager.getMetricsService();

ServiceManager 还负责对各种服务进行初始化和启动,例如:

ServiceManager.InitConf initConf = new ServiceManager.InitConf();
ServiceManager.getInstance().init(initConf);
ServiceManager.getInstance().start();

这里的 InitConf 是初始化配置对象,它包含了 Nacos 启动时需要的一些配置信息。ServiceManager 在初始化时会根据这些配置信息来创建各种服务实例,然后在启动时将这些服务启动起来,以便 Nacos 可以正常运行。

ServiceManager 是 Nacos 2.1.3 中非常重要的一个组件,它负责整个 Nacos
服务的启动、管理和停止等工作。在使用 Nacos 时,我们可以通过 ServiceManager 来获取各种服务的实例,并通过它们来访问Nacos 的配置、注册中心和命名服务等功能。

3. ClusterAgent

ClusterAgent类是集群代理,其主要负责将服务实例的注册请求广播给其他Nacos节点。

在ClusterAgent类中,服务实例的注册主要通过sendBeat方法实现,该方法的实现流程如下:

(1)首先获取当前节点的注册中心地址。

(2)然后获取当前节点的集群信息。

(3)通过集群信息获取其他Nacos节点的地址。

(4)逐个向其他Nacos节点发送注册请求。

二、服务实例的心跳

在Nacos 2.1.3中,服务实例的心跳主要通过InstanceBeatCheckTask类实现。

InstanceBeatCheckTask类继承自AbstractExecuteThread类,其主要负责执行服务实例的心跳检测任务。在InstanceBeatCheckTask类中,心跳检测任务的实现流程如下:

(1)首先获取服务实例对应的Instance对象。

(2)如果Instance对象的状态为DOWN,则直接返回。

(3)否则,向注册中心发送心跳请求。

(4)如果心跳请求失败,则将Instance对象的状态设置为DOWN。

三、服务实例的发现

在Nacos 2.1.3中,服务实例的发现主要通过以下几个类实现:

1. NamingProxy

NamingProxy类是服务发现的核心类,其主要负责向注册中心发送服务发现请求,并返回服务实例的信息。

在NamingProxy类中,服务发现的核心方法是getAllInstances方法,该方法的实现流程如下:

(1)首先构造服务发现请求。

(2)然后向注册中心发送服务发现请求。

(3)接收并解析注册中心的响应,获取服务实例的信息。

(4)返回服务实例的信息。

2. ServerListManager

ServerListManager类是服务列表管理器,其主要负责管理注册中心的地址列表。

在ServerListManager类中,服务列表的管理主要通过loadServerList方法实现,该方法的实现流程如下:

(1)首先获取当前节点的注册中心地址。

(2)如果当前节点的注册中心地址不存在,则从其他Nacos节点获取注册中心地址列表。

(3)将注册中心地址列表保存到本地缓存中。

(4)定期从其他Nacos节点获取注册中心地址列表,以保证地址列表的最新性。

3. ServiceInfoHolder

ServiceInfoHolder类是服务信息持有者,其主要负责保存服务的详细信息,包括服务名、服务实例列表、服务配置信息等。

在ServiceInfoHolder类中,服务信息的保存主要通过registerService和updateService方法实现,其实现流程如下:

(1)将服务信息封装为Service对象。

(2)将Service对象保存到本地缓存中。

(3)通过ClusterAgent向其他Nacos节点发送注册请求。

(4)如果服务信息发生变化,则通过ClusterAgent向其他Nacos节点发送更新请求。

四、服务实例的负载均衡

在Nacos 2.1.3中,服务实例的负载均衡主要通过以下几个类实现:

1. LoadBalancer

LoadBalancer类是负载均衡器,其主要负责根据负载均衡策略选择服务实例。

在LoadBalancer类中,负载均衡的核心方法是chooseInstance方法,该方法的实现流程如下:

(1)首先根据服务名获取服务实例列表。

(2)然后根据负载均衡策略选择服务实例。

(3)如果选择的服务实例状态为DOWN,则重新选择服务实例。

(4)返回选择的服务实例。

2. HealthCheckProcessor

HealthCheckProcessor类是健康检查处理器,其主要负责处理服务实例的健康检查请求。

在HealthCheckProcessor类中,健康检查的核心方法是process方法,该方法的实现流程如下:

(1)首先获取服务实例对应的Instance对象。

(2)然后根据健康检查请求更新Instance对象的状态。

(3)如果Instance对象的状态发生变化,则通过ClusterAgent向其他Nacos节点发送更新请求。

总的来说,Nacos 2.1.3的服务注册与发现机制涉及到的类和实现流程比较复杂,需要深入理解其核心源码才能更好地使用和开发Nacos。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/762909.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

javascript 将json数据导出excel

<el-button type"primary" plain v-on:click"jsonToExcel();">导出</el-button>jsonToExcel() {const data this.AlarmData;let head "城市,站点,时间,A相电流(A),B相电流(A),C相电流(A),SO2压力(MPa),CO压力(MPa),NOX压力(MPa),A相电压…

Activity引擎(初次学习与总结梳理全记录,包括易混淆知识点分析,常用报错解决方案等)

最近工作需要使用Acticity框架处理审批业务&#xff0c;简单了解后能虽能很快的上手&#xff0c;但是对于Activity的整体认识并不够&#xff0c;特此花费很多精力全面的学习并记录。包含对很多的概念的第一次理解过程&#xff1b;对知识点的混淆地方的梳理&#xff1b;对实践过…

mysql索引优化和锁

mysql索引优化和锁 IO操作与索引 IO操作上数据库性能的瓶颈之一&#xff0c;每次进行IO操作都需要消耗时间和资源。 核心:尽量减少 IO 操作的次数 读取次数少且读取量少是优化IO操作的核心目标。采用分块读取和局部性原理。 分块读取&#xff1a;将磁盘上的数据划分为若干…

黑马程序员编著过哪些教材?

黑马程序员是一家知名的IT培训机构&#xff0c;他们发布了许多教材和课程。 《Python入门教程》&#xff1a;介绍Python编程语言的基础知识和常用技巧。 《Java从入门到精通》&#xff1a;全面介绍Java编程语言的基础知识和高级特性。 《Web前端开发教程》&#xff1a;涵盖HT…

JDK压缩包安装,tomcat压缩包安装

1.解压JDK后进入我的电脑高级设置 2.新建系统变量&#xff08;变量名为JAVA_HOME&#xff0c;值为jdk文件夹的绝对地址&#xff09; 3.再次新建系统变量&#xff08;变量名为CLASSPATH&#xff0c;值为.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar&#xff09; 4.进入系…

教你如何快速准确地掌握AI最新技术

文章整理自&#xff1a;https://twitter.com/jbhuang0604/status/1426039195542360070?s21 人工智能领域如何follow最新技术&#xff1f;这应该是咱们这个行业非常关心的问题之一吧。 当你刚开始进行研究时&#xff0c;会发现每年都有成千上万的论文&#xff0c;如何在这些海…

代码随想录二刷day55 | 动态规划之子序列 392.判断子序列 115.不同的子序列

day55 392.判断子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组 115.不同的子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历…

python+allure+jenkins

目录 前言 在 python 中使用 allure 1. 安装 pytest 2. 安装 pytest-allure-adaptor 3. 使用 pytest 执行测试用例并生成 allure 中间报告&#xff08;此步骤可以省略&#xff0c;因为在 jenkins job 中会配置执行类似的命令&#xff09; 4. Jenkins 中安装Allure Jenkin…

测试老鸟整理,Jmeter常用线程组+场景实例,一篇速通测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Jmeter中通过线程…

FITC标记牛血清白蛋白(FITC-BSA)溶解性

FITC-BSA是一种常用的荧光探针&#xff0c;用于生物化学和细胞生物学研究。FITC-BSA具有溶解性&#xff0c;可以在溶液中均匀分布。 溶解性1&#xff1a; FITC标记的牛血清白蛋白&#xff08;FITC-BSA&#xff09;在适当的条件下具有良好的溶解性。FITC-BSA通常以固体形式供应…

概率论的学习和整理18:为什么 P(至少成功1次) = Σ P(几何分布) ,总结几何分布和连续失败概率的关系,二项分布和累计成功k次的关系

目录 1 先说结论&#xff1a; 2 Σ几何分布的P(xn) P(n次试验至少成功1次) 2.1 几何分布的概率 2.2 这个是可以证明的&#xff0c;下面是推导过程 2.3 怎么理解呢&#xff1f; 3 另外&#xff0c;P(累计成功k次) ΣP(成功k次的二项分布) 3.1 成功k次的概率 和 累计成…

C# NPOI读取Excel中文乱码

Win11, 程序中需要从Excel表格读取中文内容&#xff0c;实测发现有中文乱码问题&#xff1a; class name:??Vege 奇怪的问号&#xff0c;原文是“蔬菜Vege”。 网上找了一圈&#xff0c;没找到NPOI中文乱码的解决方案&#xff0c;普遍都是比较顺利没遇到中文乱码问题。 那…

DP4057替代TP4057 500mA双灯指示防反接锂电充电管理IC

DP4057 是一款完整的单节锂离子电池充电器&#xff0c;带电池正负极反接保护&#xff0c;采用恒定电流/恒定电压线性控制。其 SOT26封装与较少的外部元件数目使得 DP4057 成为便携式应用的理想选择。DP4057可以适合 USB电源和适配器电源工作。由于采用了内部PMOSFET架构&#x…

ubuntu 20.04, 22.04网络配置比较

1.ubuntu 20.04网络配置&#xff0c;配置静态IP&#xff1a;切换roote用户&#xff0c;vi /etc/netplan/00-installer-config.yaml&#xff0c;修改网络配置&#xff0c;格式如下&#xff1a; network: ethernets: ens33: dhcp4: false addresses: [172.22.…

机器学习31:《推荐系统-IV》深度神经网络DNN

在《机器学习29&#xff1a;《推荐系统-II》协同过滤》一文中&#xff0c;笔者介绍了如何使用矩阵分解来学习嵌入。矩阵分解具有一些局限性&#xff1a; 基础矩阵分解只用了 UserID&#xff08;QueryID&#xff09; 和 ItemID 两个维度的信息&#xff0c;所有学到的知识都蕴含在…

SQL-每日一题【596.超过五名学生的课】

题目 表: Courses 编写一个SQL查询来报告 至少有5个学生 的所有班级。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求查询至少有五个学生所在的班级&#xff0c;我们就可以先用group by class 对班级先分一下组。 2。分好组后&#xff0c;我…

《Communication-Efficient Learning of Deep Networks from Decentralized Data》

Communication-Efficient Learning of Deep Networks from Decentralized Data 这篇文章算是联邦学习的开山之作吧&#xff0c;提出了FedAvg的算法&#xff0c;文中对比了不同客户端本地训练次数&#xff0c;客户端训练数据集划分的影响。 0. Abstract 现代移动设备可以获取大…

永久区和元空间的区别

一文搞懂JVM之 方法区、永久代、元空间三者的区别 - 知乎 元空间和永久代的区别-腾讯云开发者社区-腾讯云 方法区和永久区/元空间之间的关系 - 简书 方法区(Method Area),是JVM规范中提出的一个(概念)&#xff0c;用于存储类信息、常量池、静态变量、JIT编译后的代码等。 Th…

“周杰伦概念股”IPO,巨星传奇市值42亿港元

“周杰伦概念股”巨星传奇&#xff0c;一波三折终上市。 今日&#xff08;7月13日&#xff09;&#xff0c;巨星传奇集团有限公司&#xff08;下称“巨星传奇”&#xff0c;06683.HK&#xff09;正式挂牌港交所。 此前&#xff0c;巨星传奇于2021年9月、2022年3月和2022年10月…

【广州华锐互动】发动机零件拆装VR虚拟学习平台

随着科技的飞速发展&#xff0c;虚拟现实(VR)技术正在各行各业中发挥越来越重要的作用。在工业教育领域&#xff0c;发动机零件拆装VR虚拟学习平台为学生提供了一种全新的学习方式&#xff0c;使他们能够在安全、低成本的环境中进行实践操作&#xff0c;从而提高技能&#xff0…