微服务-Nacos服务注册与发现的原理

193 阅读3分钟

一、Nacos简介

  • 官网地址:nacos.io/
  • Nacos:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用
  • 以下的配置是正确安装好JDK11、并配置JAVA_HOME环境变量的情况下的(以下安装适配于JDK11,和nacos-server-2.0.4版本的) 注意:版本一定要兼容否则会出问题

二、注册中心的原理

在微服务远程调用的过程中,包括两个角色:

  • 服务提供者:提供接口供其它微服务访问。
  • 服务消费者:调用其它微服务提供的接口。

image.png 当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?

  • 服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)
  • 当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除
  • 当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表
  • 当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表

三、本地安装Nacos-2.0.4

3.1.前置条件

正确安装好JDK11、并配置JAVA_HOME环境变量

3.2 安装Nacos

去官网nacos.io/下载Nacos-2.0.4版本的压缩包,解压到没有中文目录下即可

3.3.导入SQL

在官网下载的压缩包的config里有sql文件:

  1. 创建名为nacos的数据库
  2. 导入nacos\conf\nacos-mysql.sql文件到nacos数据库中
  3. 修改nacos\conf\application.properties配置文件

image.png

3.4启动Nacos

进入nacos/bin目录下调用终端

  1. windows输入命令
    startup.cmd -m standalone
  2. mac/Linux输入命令
    sh startup.sh -m standalone
  3. 启动成功如下

image.png

四、微服务中进行服务注册

这里以item-service(商品服务)和cart-service(购物车服务)这拆分过的微服务

4.1在item-servicepom.xml中添加依赖:

<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

4.2在item-service的yaml文件中进行配置

spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848 # nacos地址

4.3为了测试一个服务多个实例的情况可以再次为这个服务创建一个实例,让他随机访问这两个实例,减轻服务器的访问压力

image.png image.png 1728651811827.png

4.4重启这两个实例访问nacos地址

image.png

五、服务发现

cart-service中的pom.xml中添加下面的依赖:

<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

cart-serviceapplication.yml中添加nacos地址配置:

spring:
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848

服务发现需要用到一个工具,DiscoveryClient 这个是取出服务中所有的实例的信息,SpringCloud已经帮我们自动装配,我们可以直接注入使用在这里进行调用 RestTemplate进行远程调用:

@Resoure
DiscoveryClient discoveryClient
@resoure
RestTemplate restTemplate
 List<ServiceInstance> instances = discoveryClient.getInstances("item-service");
        int index = RandomUtil.randomInt(instances.size());
        ServiceInstance instance = instances.get(index);
        log.info("调用的地址,url={}" , instance.getUri());
        ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
                instance.getUri()+"/items?ids={ids}",
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<ItemDTO>>() {},
                Map.of("ids", CollUtils.join(itemIds, ",")));
        // 2.2.判断当前远程调用是否正常
        if(!response.getStatusCode().is2xxSuccessful()){
            // 查询失败,直接结束
            return;
        }
        List<ItemDTO> items = response.getBody();
        if (CollUtils.isEmpty(items)) {
            return;
        }