相关文章推荐
淡定的盒饭  ·  用 Python ...·  7 月前    · 
爱健身的杯子  ·  JSON 对象 | 菜鸟教程·  1 年前    · 
图解Nacos,注册中心演变 + Nacos核心功能

图解Nacos,注册中心演变 + Nacos核心功能

大家好,我是哪吒。

本系列为 SpringCloud微服务系列 ,上一篇学习了 图解Nginx,系统架构演变 + Nginx反向代理与负载均衡 ,读哪吒编程,品技术人生。

一、什么是Nacos?

一个更易于构建云原生应用的动态服务发现、服务配置和服务管理平台。

Nacos的关键特性:

Nacos的关键特性

二、注册中心演变及其设计思想

1、RestTemplate调用远程服务

如果此时,服务端接口接口名或参数或请求方式更改了,那么就得同步修改此restTemplate方法,感觉 很麻烦

RestTemplate调用远程服务
@SpringBootTest
class Test {
   @Resource
   private RestTemplate restTemplate;
   @Test
   void testSimple()  {
      // 请求地址
      String url = "http://www.nzbc.com/updateUser";
      // 要发送的数据对象
      User user = new User();
      user.setUserId(1);
      user.setName("哪吒编程");
      user.setMsg("读哪吒编程,品技术人生");
      // 发送post请求
      User result = restTemplate.postForObject(url, user, User.class);
      System.out.println(result);

2、通过Nginx维护服务列表(upStream)

通过Nginx维护服务列表(upStream) ,如果服务较多的话,在Nginx通过upStream的方式去配置的话,Nginx配置文件会变得非常的难以维护。

3、通过Nacos实现注册中心

Nacos注册中心

这种是 最简单的Nacos注册中心 ,有若干个服务,都注册到Nacos注册中心,调用之前,先到Nacos获取对应接口,然后进行实际的调用。

但是,思考一个问题,如果Nacos宕机了,怎么办?如果从Nacos获取到接口后,调用服务2时,服务2宕机了,怎么办?

4、心跳版Nacos

心跳版Nacos

心跳版Nacos ,服务1和服务2和Nacos之间维护一个心跳关系,每5秒跳一次,频率不能太快或者太慢,否者会嗝屁的。

如果Nacos在 5秒 内没有收到心跳,则表示服务挂了,Nacos 会下线此服务

对于超过 15秒 没有收到客户端心跳的服务实例,会将它的 healthy属性置为false ,客户端无法调用healthy为false的服务。

如果超过 30秒 没有收到心跳,Nacos会直接将此 服务剔除

也可以通过服务端主动注销的方式,停止注册。

服务1调用服务2时,服务1会通过定时任务到Nacos中获取在线的服务,保证所调用的服务一直都是健康在线的状态。

获取到之后,用缓存将其保存起来,然后通过负载均衡器调用服务2,此时,将不再使用服务端的负载均衡Nginx了。

三、Nacos Discovery

SpringBoot中引入Nacos Discovery,实现与Nacos的无缝连接 ,Nacos Discovery可以将服务自动注册到Nacos服务端,并且能够动态感知此服务,并刷新服务列表。并将服务的host、port、URL等信息注册到Nacos。

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

Nacos 的配置项信息:

四、Nacos核心功能

Nacos核心功能

1、服务注册

Nacos Client会通过发送REST请求向Nacos Server注册自己的服务,提供自身的元数据 ,比如host、port、url等信息,Nacos Server在收到注册请求后,会将这些数据信息存储在一个双层的内存map中。

2、服务心跳

服务注册后,服务消费者和Nacos Server之间会维护一个心跳,定时通知server,此服务还活着,防止被剔除掉。

3、服务同步

Nacos Server集群之间会互相同步已注册的服务,用来保证服务列表的一致性。

4、服务发现

服务消费者在调用服务提供者的服务时,会发送一个REST请求到Nacos Server,获取健康的服务列表,然后将其缓存到本地,同时开启一个定时任务,定时访问Nacos Server,然后更新本地缓存。

5、服务健康检查

Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况 ,对于超过15秒没有收到客户端心跳的服务实例,会将它的healthy属性置为false,客户端无法调用healthy为false的服务,如果超过30秒没有收到心跳,Nacos会直接将此服务剔除。

五、作为注册中心

1、 Nacos 目前功能最全,用的也最多;

2、 Eureka ,因为挺更的缘故,比较新的技术都不支持了,目前很多公司都将Eureka换成Nacos了,不推荐使用;

3、 Zookeeper ,用的最多的地方就是和Dubbo一起使用,不支持负载均衡策略,但可以通过其它组件实现;

4、 Consul 支持的也很多;

CAP,C一致性,A可用性,P分区容错性
Nacos Eureka Zookeeper Consul
一致性协议 CP + AP CP AP CP
访问协议 HTTP/DNS HTTP TCP HTTP/DNS
健康检查 TCP/HTTP/MYSQL/Client Beat Client Beat Keep Live TCP/HTT[/gRPC/Cmd
负载均衡策略 权重/metadata/Seletor Ribbon - Fabio
雪崩保护
自动注销 支持 支持 支持 支持
监听 支持 支持 支持 支持
多数据中心 支持 支持 支持 不支持
跨注册中心同步 支持 不支持 不支持 支持
Spring Cloud集成 支持 支持 支持 支持
Dubbo集成 支持 不支持 支持 支持
K8S集成 支持 不支持 支持 不支持

六、作为配置中心

1、SpringBoot集成Nacos

Nacos使用key/value形式存储配置信息,为分布式系统中的外部化配置提供服务支持。

(1)maven文件

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

(2)配置文件

spring.application.name=nacos-config
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
blog.name=哪吒编程
blog.language=java

(3)主方法启动类

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApplication.class, args);
        String name = applicationContext.getEnvironment().getProperty("blog.name");
        String language = applicationContext.getEnvironment().getProperty("blog.language");
        System.err.println("名字 :"+name+"; 擅长技术: "+language);
}

2、支持配置的动态更新

一秒刷新一次。

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(ProviderApplication.class, args);
        while(true) {
            //当动态配置刷新时,会更新到 Enviroment中,因此这里每隔一秒中从Enviroment中获取配置
            String name = applicationContext.getEnvironment().getProperty("blog.name");