Nacos服务注册与发现的原理
如果商品微服务被调用较多,为了应对更高的并发,我们进行了多实例部署,如图:
此时,每个item-service的实例其IP或端口不同,问题来了:
- item-service这么多实例,cart-service如何知道每一个实例的地址?
- http请求要写url地址,cart-service服务到底该调用哪个实例呢?
- 如果在运行过程中,某一个item-service实例宕机,cart-service依然在调用该怎么办?
- 如果并发太高,item-service临时多部署了N台实例,cart-service如何知道新实例的地址?
为了解决上述问题,就必须引入注册中心的概念了,接下来我们就一起来分析下注册中心的原理。
注册中心
注册中心原理
在微服务远程调用的过程中,包括两个角色:
- 服务提供者:提供接口供其它微服务访问,比如item-service
- 服务消费者:调用其它微服务提供的接口,比如cart-service
在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了注册中心的概念。注册中心、服务提供者、服务消费者三者间关系如下:
服务注册
在微服务架构中,服务提供者需要将自己的服务注册到服务注册中心,以便服务消费者能够发现并调用这些服务,以Nacos作为注册中心,提供了注册服务的功能。
服务注册原理
服务注册的原理如下:
- 服务提供者启动时,将自己的服务实例信息(如服务名称、IP地址、端口号等)通过RESTful API方式发送给Nacos服务端。
- Nacos服务端接收到服务提供者发送的注册请求后,将服务实例信息存储在注册中心的数据库中,同时将这些信息缓存到内存中,以便快速查询。
- Nacos服务端将注册信息存储在两个地方:一个是持久化的存储(如MySQL、Derby等数据库),用于服务实例的持久化存储;另一个是内存中的缓存,用于快速的服务实例查询。
- 注册成功后,服务提供者会定时向Nacos发送心跳请求,以表明自己的服务实例还在运行中。Nacos服务端根据心跳信息更新服务实例的状态,以便服务消费者能够获取到最新的服务实例信息。
- 服务消费者通过Nacos服务端的RESTful API查询服务注册中心获取到最新的服务实例信息(如服务名称、IP地址、端口号等),从而能够调用服务提供者。
服务注册实现
引入依赖
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置Nacos
server:
port: 8081 # 端口号
spring:
application:
name: item-service # 服务名称
cloud:
nacos:
server-addr: 127.0.0.1:8848 # Nacos服务器地址
在服务注册的项目上的引导类(启动类)上使用@EnableDiscoveryClient
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceProviderApplication.class, args);
}
}
服务发现
在微服务架构中,服务消费者需要从服务中心服务提供者的信息,以便能够调用相对应的服务,以Nacos作为服务注册中心,提供了服务发现的功能。
服务发现原理
服务发现的原理如下:
- 服务消费者启动时,通过RESTful API方式向Nacos服务端发送服务发现请求,请求包括服务名称、版本号、环境等信息。
- Nacos服务端接收到服务发现请求后,从注册中心的缓存或持久化存储中查询符合请求条件的服务实例信息,并返回给服务消费者。
- 服务消费者根据返回的服务实例信息,选择一个合适的服务提供者进行调用。Nacos还提供了负载均衡策略,可以根据配置的负载均衡算法进行服务实例的选择。
- 服务消费者在调用服务提供者时,可以直接使用服务实例的网络地址(如IP地址、端口号)进行调用,从而实现服务间的通信。
服务发现实现
服务的消费者要去nacos订阅服务,这个过程就是服务发现,步骤如下:
- 引入依赖
- 配置Nacos地址
- 发现并调用服务
引入依赖
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置Nacos
server:
port: 8082 # 端口号
spring:
application:
name: cart-service # 服务名称
cloud:
nacos:
server-addr: 127.0.0.1:8848 # Nacos服务器地址
可以发现,这里Nacos的依赖于服务注册时一致,这个依赖中同时包含了服务注册和发现的功能。
因为任何一个微服务都可以调用别人,也可以被别人调用,即可以是调用者,也可以是提供者。
因此,服务调用者必须利用负载均衡的算法,从多个实例中挑选一个去访问。常见的负载均衡算法有:
- 随机
- 轮询
- IP的hash
- 最近最少访问
- ...
这里我们可以选择最简单的随机负载均衡。
@Slf4j
@RestController
public class MyController {
@Autowired
private DiscoveryClient discoveryClient
@GetMapping("/get")
public String getServiceUrl() {
//发现item-service服务的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
//负载均衡,挑选一个实例
ServiceInstance instance = instances.get(RandomUtil.randomInt(instances.size()));
String urlResult = instance.getUri().toString();
log.info("ServiceUrl:{}",urlResult);//ServiceUrl:http://192.168.36.100:8081
return urlResult;
}
}
恭喜!获取到了我们需要服务提供者的IP和端口。