文章目录
- 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 世界
- 业务大图:利用当前特性可以支持的业务场景,及其最佳实践
- 生态大图:系统梳理 Nacos 和主流技术生态的关系
- 优势大图:展示 Nacos 核心竞争力
- 战略大图:要从战略到战术层面讲 Nacos 的宏观优势
1. 原理解析
1.1 服务注册与发现流程
一、服务注册流程
服务注册是指将服务实例信息注册到Nacos服务器上,以便于其他服务或客户端发现和调用该服务。Nacos的服务注册机制主要基于HTTP和Raft协议实现,其注册流程如下:
- 客户端向注册中心发送注册请求
当一个服务实例启动时,它会向指定的Nacos服务器发送一个注册请求。注册请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。
- 注册中心接收并处理注册请求
当Nacos服务器接收到注册请求后,它会将服务实例信息保存到注册中心的数据存储中。同时,它会向其他注册中心广播该服务的信息,以便于其他服务或客户端发现和调用该服务。
- 客户端定期发送心跳请求
为了保持服务注册状态的有效性,Nacos客户端会通过心跳机制定期向Nacos服务器发送心跳请求。心跳请求包含服务实例的IP地址、端口号、服务名、健康状态等信息。当Nacos服务器接收到心跳请求后,它会更新服务实例的健康状态,并将更新后的信息广播给其他注册中心。
二、服务发现流程
服务发现是指通过Nacos服务器查找服务实例,以便于其他服务或客户端调用该服务。Nacos的服务发现机制主要基于DNS和HTTP实现,其服务发现流程如下:
- 客户端向Nacos服务器发起服务发现请求
当一个服务客户端需要发现一个服务时,它会向Nacos服务器发送一个服务发现请求。服务发现请求包含服务名、集群名、命名空间等信息。
- Nacos服务器返回服务实例列表
当Nacos服务器接收到服务发现请求后,它会从数据存储中查找符合条件的服务实例,并返回服务实例的IP地址和端口号列表。
- 客户端进行负载均衡和调用
当客户端接收到服务实例列表后,它会通过负载均衡算法选择一个服务实例,并发起调用请求。如果调用失败,客户端将会重新选择另外一个服务实例进行调用,直到调用成功或者所有服务实例都被尝试过。
三、注册中心高可用性机制
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进行服务注册与发现。
- 服务提供者注册服务
服务提供者启动后,可以通过以下代码将服务实例信息注册到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);
}
}
- 服务消费者发现服务
服务消费者启动后,可以通过以下代码从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);
}
}
- 服务负载均衡
Nacos支持多种负载均衡策略,包括随机、轮询、加权轮询等。我们可以通过以下代码来设置负载均衡策略:
@Configuration
public class NacosConfig {
@Bean
public IRule loadBalanceRule() {
return new RandomRule();
}
}
以上代码将负载均衡策略设置为随机。我们也可以将负载均衡策略设置为其他策略,例如轮询、加权轮询等。
1.2 服务集成
要将 Nacos 2.1.3 作为 Spring Boot 应用程序的注册中心,可以按照以下步骤进行集成:
-
添加 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>
-
在
application.properties
或application.yml
配置文件中添加 Nacos 注册中心的相关配置信息,例如:spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 spring.cloud.nacos.discovery.namespace=public
这里的
server-addr
指定了 Nacos 服务器的地址和端口号,namespace
指定了 Nacos 的命名空间。 -
在启动类上添加
@EnableDiscoveryClient
注解,开启服务注册发现功能,例如:@SpringBootApplication @EnableDiscoveryClient public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
-
在需要注册到 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) {
// ...
}
}
- 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);
}
});
}
- 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());
}
- 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;
}
- 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);
}
});
}
- 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());
}
- 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。