SpringCloud之Nacos的学习、快速上手
1、什么是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的推送更新,导致只从缓存中获取实例信息,就会导致我们后面业务调用异常