基本介绍
在 Nacos 中,注册表是其中一个重要的组件,用于管理服务的注册和发现。
注册表是一个存储服务实例信息的数据库,它记录了所有已注册的服务实例的相关信息,包括服务名称、IP 地址、端口号等。
通过注册表,服务提供者可以将自己的服务注册到平台上,而服务消费者可以从注册表中获取到可用的服务列表.注册表的作用是实现服务的自动发现和动态调用,为微服务架构的实施提供支持。
注册表核心概念
- 服务实例:注册表中的基本单位,代表一个运行中的服务。每个服务实例都有一个唯一的标识符,可以通过该标识符在注册表中进行查找和访问。
- 服务名称:每个服务实例都属于一个特定的服务名称,服务名称是在服务注册时定义的,用于对服务进行分类和管理
- IP 地址: 服务实例的网络地址,用于标识服务的运行位置
- 端口号:服务实例所监听的端口,用于接收服务请求
- 健康状态:注册表中的服务实例会定期向平台报告自己的健康状态,以确保只有可用的服务实例被提供给消费者
- 元数据:注册表中的服务实例还可以携带一些额外的元数据,用于描述服务的特性和配置信息。
源码解析注册表的构成
主要代码入口位于:naming模块中的com.alibaba.nacos.naming中的controller中,找到register方法
@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils
.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
NamingUtils.checkServiceNameFormat(serviceName);
final Instance instance = parseInstance(request);
serviceManager.registerInstance(namespaceId, serviceName, instance);
return "ok";
}
查看ServiceManager的结构 :引入了一个多层map,最外层的String指的是Namespace,然后对应的值Map就是根据不同环境的服务,再分层就是组Group——>对应的Service,Service可能包含多种服务
@Component
public class ServiceManager implements RecordListener<Service> {
/**
* Map(namespace, Map(group::serviceName, Service)).
*/
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
跟进查看Service(服务):Service中里面用了一个HashMap,存储服务的集群,对应Cluster实例
//String集群名字,Cluster实例
private Map<String, Cluster> clusterMap = new HashMap<>();
根据查看Cluster(实例):发现最终的实例使用HashSet存储起来的,有临时和非临时两种情况
//永久实例,Set存服务
@JsonIgnore
private Set<Instance> persistentInstances = new HashSet<>();
//临时实例
@JsonIgnore
private Set<Instance> ephemeralInstances = new HashSet<>();
Nacos是多级存储模型,最外层通过namespace来实现环境隔离,然后是group分组,分组下就是服务,一个服务有可以分为不同的集群,集群中包含多个实例。
- 其注册表结构为一个Map,类型是:Map<String, Map<String, Service>>
- 外层key是namespace_id,内层key是group+serviceName,
- Service内部维护一个Map,结构是:Map<String,Cluster>,key是clusterName,值是集群信息
- Cluster内部维护一个Set集合,元素是Instance类型,代表集群中的多个实例。
首先最外层是一个Map,结构为:
Map<String, Map<String, Service>>
:
key:是namespace_id,起到环境隔离的作用。namespace下可以有多个group
value:又是一个
Map<String, Service>
,代表分组及组内的服务。一个组内可以有多个服务
key:代表group分组,不过作为key时格式是group_name:service_name
value:分组下的某一个服务,例如userservice,用户服务。类型为
Service
,内部也包含一个Map<String,Cluster>
,一个服务下可以有多个集群
key:集群名称
value:
Cluster
类型,包含集群的具体信息。一个集群中可能包含多个实例,也就是具体的节点信息,其中包含一个Set<Instance>
,就是该集群下的实例的集合
Instance:实例信息,包含实例的IP、Port、健康状态、权重等等信息
注册表作用
- 服务发现:注册表充当了服务发现的角色,服务提供者将自己的服务实例注册到注册表中,而服务消费者可以从注册表中获取到可用的服务列表,从而实现服务的自动发现和调用
- 负载均衡:注册表中会记录多个相同服务名称的服务实例,消费者可以通过负载均衡算法从中选择一个合适的服务实例进行调用,从而实现服务的负载均衡
- 故障转移:当某个服务实例发生故障或下线时,注册表可以快速检测到并将其从可用服务列表中移除,从而避免将请求发送到不可用的服务实例上
- 动态扩展:当需要增加新的服务实例时,只需将其注册到注册表中即可,而不需要修改服务消费者的代码,从而实现服务的动态扩展。
注册表工作流程
- 服务提供者将自己的服务实例注册到注册表中,包括服务名称、IP 地址、端口号等信息
- 服务消费者从注册表中获取可用的服务列表,并选择一个合适的服务实例进行调用。
- 服务消费者通过负载均衡算法选择的服务实例,将请求发送到该实例的 IP 地址和端口号
- 服务提供者接收到请求后进行处理,并将响应发送给服务消费者
- 注册表定期检测服务实例的健康状态,如果发现有服务实例故障或下线,会将其从可用服务列表中移除