SpringCloud之Nacos的学习、快速上手

1、什么是Nacos

Nacos是阿里的一个开源产品,是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案,用来实现配置中心和服务注册中心。

Nacos 快速开始

2、安装运行nacos

nacos下载地址

下载地址: https://github.com/alibaba/nacos/releases
zip为Windows压缩包        tar.gz为linux压缩包

个人百度网盘分享链接:https://pan.baidu.com/s/1RTNA0Gx5chpyb-HXCOuJuw?pwd=8848 
提取码:8848 

下载解压后运行nacos    进入bin目录  执行下面命令即可        -m为启动模式,设置为单机模式运行

startup.cmd -m standalone

如果不想每次输入-m standalone可以右键startup.cmd使用文本打开修改配置即可

这样我们只需要双击startup.bat文件即可自动在单机模式下运行nacos

默认端口8848        

浏览器访问localhost:8848/nacos即可进入nacos控制台        账号密码默认都是nacos

3、Nacos注册中心的使用

将微服务注册到nacos

准备了两个微服务分别是订单微服务商品微服务

需要引入的依赖为

<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
   <version>2.2.5.RELEASE</version>
</dependency>

3.1在application.yml文件中需要配置服务名称和nacos连接地址        

注意:服务名称不能重复        服务名称不能没有

重复则nacos视为一个服务        没有nacos扫描不到则服务列表不显示

spring:
  application:
    name: product-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

3.2在启动类是加上注解@EnableDiscoveryClient(不加也可以)

@SpringBootApplication
@EnableDiscoveryClient
public class OrderServer {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer.class,args);
    }
}

启动两个微服务

观察nacos控制台在服务列表可以看到刚刚启动的两个微服务

4、Nacos注册中心的原理

Nacos将服务可以分为服务消费者服务提供者        

在我的项目中现在有订单和商品微服务,在订单服务中需要调用商品服务查询商品信息

则可以将订单微服务称为服务消费者,将商品微服务称为服务提供者

4.1服务注册流程:

1、product-service服务向nacos注册中心进行服务注册,同时对nacos上现有的已经存在的服务进行服务拉取,并将拉取到的服务列表缓存到本地列表

2、注册成功后定时向nacos发送心跳,告诉nacos这个服务正常运行

3、同时,order-service服务也执行上述操作,注册服务、拉取服务、缓存服务到本地、定时发送心跳

 4.2服务怎么从注册中心获取呢

@RestController
@Slf4j
public class NacosController {

    //注入服务发现接口
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("test")
    public void test(){
        //获取服务名称为product-service的服务,得到的是一个List的实例集合
        //因为有可能有多个实例
        List<ServiceInstance> instances = discoveryClient.getInstances("order-service");
        //获取第一个实例,也就是获取的实例列表中的第一个实例
        ServiceInstance serviceInstance = instances.get(0);
        //获取这个实例的端口
        int port = serviceInstance.getPort();
        //获取这个实例的访问地址
        String host = serviceInstance.getHost();
        log.info("获取服务名为order-service的第一个服务:{}",serviceInstance);
        log.info("获取服务名为order-service的第一个服务port:{}",port);
        log.info("获取服务名为order-service的第一个服务host:{}",host);
    }
}

我们对这个接口进行访问

4.3对接口进行调用

在需要调用的服务的启动类上加上@Bean交给Spring管理

@SpringBootApplication
public class OrderServer {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer.class,args);
    }
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

然后在我们的order-service业务中进行调用

@Service
@Slf4j
public class OrderServiceImpl implements IOrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;
    @Override
    public void createOrder(Long productId,Long userId) {
        log.info("接收到{}号商品的下单请求,接下来调⽤商品微服务查询此商品信息",
                productId);
        //远程调⽤商品微服务,查询商品信息
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        ServiceInstance serviceInstance = instances.get(0);
        int port = serviceInstance.getPort();
        String host = serviceInstance.getHost();
        Product product = restTemplate.getForObject("http://" + host + ":" + port + "/product/" + productId, Product.class);
        log.info("查询到{}号商品的信息,内容是:{}", productId,JSON.toJSONString(product));
        
    }
}

我们写一个方法执行上面的逻辑即可

@RestController
@Slf4j
public class OrderController {
    @Autowired
    private IOrderService orderService;

    @RequestMapping("/save")
    public void order(Long pid,Long uid){
        return orderService.createOrder(pid, uid);
    }
}

当我们访问这个接口后,查看控制台

已经成功调用商品服务

当然这样服务调用很麻烦,所以后面我们会使用openfeign替换

4.4当nacos检测到某个服务出现问题

此时我们查看nacos控制台

两个服务都正常

当我们停掉product-service服务        当大概十五秒后查看nacos可以看到商品服务成为了不健康实例        这是因为nacos十五秒没有收到这个服务发送的心跳就认为这个服务是不健康的

再大概过十五秒        发现商品服务已经没有了,这是因为nacos超过三十秒没有感知到这个服务,则这个服务则会被Nacos剔除。

4.5关闭Nacos服务会怎么样

当Nacos意外停止时,还能调用服务吗

我们将商品服务和订单服务重新都启动起来

这时候我们关闭Nacos的控制台

这时候我们访问localhost:8848/nacos已经访问不到了,但是此时我们调用服务会怎么样呢?

我们继续调用刚才的/save方法

可以看到仍然获取到了商品信息,即调用到了商品服务的接口

这是因为当nacos关闭时,但是本地缓存的依然存在(在上面我们说了每次获取到服务列表后会将服务列表缓存到本地),所以才能仍然获取到这个实例的信息并进行调用。

但是当我们关闭商品服务后,测试获取商品服务的实例

@RestController
@Slf4j
public class NacosController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("test")
    public void test(){
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        ServiceInstance serviceInstance = instances.get(0);
        int port = serviceInstance.getPort();
        String host = serviceInstance.getHost();
        log.info("获取服务名为product-service的第一个服务:{}",serviceInstance);
        log.info("获取服务名为product-service的第一个服务port:{}",port);
        log.info("获取服务名为product-service的第一个服务host:{}",host);
    }
}

访问test接口

可以看到即使商品服务关闭了,但是仍能获取到商品服务的实例,这是因为缓存到本地之后,没有了nacos的推送更新,导致只从缓存中获取实例信息,就会导致我们后面业务调用异常