• SpringCloud——注册中心nacos


    四、Nacos注册中心

    4.1 初识Nacos

    Nacos是阿里巴巴的产品,也是目前SpringCloud的一个组件,相比Eureka而言,功能更加丰富,在国内受欢迎的程度也更高。

    Nacos是需要下载的,Windows下载教程如下:

    这是我在码云看到的一个热心网友分享的一个镜像,下载起来比较快,比起直接用家里的网络登录github快多了。这里,我们下载1.4.2的nacos:(镜像地址:Releases · alibaba/nacos · GitHub (xn–gzu630h.xn–kpry57d)

    Release 1.4.2 (Apr 29th, 2021) · alibaba/nacos · GitHub (xn–gzu630h.xn–kpry57d)

    进去后,我们拉到最下面,下载Windows版本的安装包,下载完成后解压到本地非中文的目录下
    在这里插入图片描述
    我解压的位置是:D:\Program Files\nacos

    nacos默认占用的端口号是:8848,如果该端口号已经被其他软件占领了,那么我们可以在 nacos/conf 目录下修改他的application.properties文件。

    server.port=8848

    nacos/target 目录下放置的是 nacos的jar包

    要想启动nacos,我们可以通过cmd进入 nacos/bin 目录下,执行下列命令:(standalone 表示单机版)

    startup.cmd -m standalone

    启动成功后,我们访问网址 http://192.168.1.103:8848/nacos/index.html

    初始账号密码都是nacos,登录成功后显示如下:

    在这里插入图片描述
    接下来,我们讲一下怎么简单的使用Nacos进行服务的注册。

    要想在SpringCloud中使用Nacos,首先,我们对在原先项目中,引入我们的SpringCloud-Alibaba管理依赖:

    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-alibaba-dependenciesartifactId>
        <version>2.2.5.RELEASEversion>
        <type>pomtype>
        <scope>importscope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后,我们要注释掉之前在order还有user服务下的eureka依赖并添加nacos依赖。

            
    
    
    
    
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    之后,我们修改user和order的配置文件,注释掉Eureka的配置信息,并修改服务注册的地址为我们的nacos:

    #eureka地址信息
    #eureka:
    #  client:
    #    service-url:
    #      defaultZone: http://127.0.0.1:8090/eureka
    
    spring:
      cloud:
        nacos:
          server-addr: localhost:8848
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    一切准备就绪后,我们重启我们的三个服务(user、user1、order),然后,我们在nacos的控制台,可以看到:
    在这里插入图片描述
    点击服务右侧详情,我们还可以看到具体的每个服务的ip和端口号等详细信息,注意了,这里用的还是Windows,但是显示的是真ip地址,而不是像Eureka那样,Windows系统下,输出计算机名。

    在这里插入图片描述
    此时,我们访问地址:localhost:8080/order/101 仍然可以正常请求到数据。
    在这里插入图片描述

    4.2 服务多级存储模型

    服务多级存储模型:服务——集群——实例

    • 服务:user微服务
    • 集群:某个机房所有的部署了user的服务器
    • 实例:具体的每个部署了user的服务器

    举个例子:服务针对的是整个user这个微服务,而我们的user微服务在各个城市假设都有机房,并且每个机房我们建立集群,每个机房中的服务器,我们都整一个user服务实例,这就构成了我们的服务多级存储模型啦!具体可以看下面的图:
    在这里插入图片描述
    看到这个模型,有些小伙伴可能会说了,要这么玩的话,那以前面的例子,在北京的order访问我们的user,整一个负载均衡,是不是平均分到北京、上海、杭州这三个地方去了,那请求那么远,速度不就慢了吗。这就是我们的服务跨集群问题。针对这个问题,nacos的做法也很简单直接,既然服务调用跨集群延迟较高,那么服务调用就让他尽可能选择本地集群的服务,当本地集群不可访问的时候,我们再去访问其他集群。

    给我们的服务实例配置集群也很简单,只需要在yaml中添加属性如下:

    spring:
    	cloud:
        	nacos:
                server-addr: localhost:8848 #nacos地址
                discovery:
                	cluster-name: GZ  #集群名称
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    我们可以在自己项目中两个User实例下将集群名称设置为SZ,再开一个实例将集群名称设置为GZ,结果如下:

    在这里插入图片描述

    4.3 NacosRule负载均衡

    我们设置order的集群为SZ。

    spring:
      cloud:
        nacos:
          server-addr: localhost:8848
          discovery:
            cluster-name: SZ
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    再尝试发送3次请求,查看日志可以发现,三个user服务都被调用了,这明显不是我们想要的结果。我们希望的是集群为SZ的order 优先向 集群同为 SZ 的 user 服务发送请求,只有在user服务宕机的情况下,我们才考虑向其他的集群发送请求。

    前面我们已经说过了,决定我们负载均衡的是Ribbon的IRule,其实Nacos也有提供一个IRule的实现类,要想实现Nacos集群内优先访问的负载均衡策略,我们可以使用Nacos包附带的NacosRule规则,在order服务的配置信息中添加对user服务请求时,IRule的配置信息如下:

    user: #请求的服务名称
      ribbon:
        NFLoadBalanceRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule  #使用的负载均衡策略
    
    • 1
    • 2
    • 3

    如此,order在访问user服务的时候,他就会优先访问同一个集群的user服务,除非同一个集群的所有user服务宕机了,那么他才会访问其他集群的user服务。

    批注:NacosRule 的请求方式是 相同集群内随机请求,如果相同集群所有服务全部宕机,那么随机请求其他集群的服务。

    这种随机请求的方式对我们现实其实是不友好的,因为首先,企业的服务器一般不会说所有服务器都是同时租的or买的,而且每一台性能都一模一样,总有快慢之分。因此,我们肯定是希望性能好的服务器,他多被请求,性能差的服务器,少接收几个请求,而不是随机式的,怎么办呢?请看:

    Nacos提供了权重配置来控制各个服务被请求的评率,具体只需要在nacos服务端,找到对应的服务,点击编辑,并修改其权重值即可(值为0~1),权重越小,被访问的概率就越小。
    在这里插入图片描述
    在这里插入图片描述

    4.4 环境隔离(namespace)

    一般用来隔离我们的各个环境,例如最简单的 生产环境、测试环境和开发环境。

    nacos默认会帮我们创建的命名空间叫public
    在这里插入图片描述
    我们也可以新建我们自己的命名空间,只需要点击左侧的命名空间
    在这里插入图片描述
    然后,点击右侧的新建命名空间,输入命名空间的名字和描述即可,命名空间的ID可以自己设置,也可以让他自动生成。
    在这里插入图片描述
    生成命名空间后,点击服务管理 》 服务列表,我们就可以看到我们的命名空间test,出现了右侧的上方了,点击即可跳转到对应的命名空间。
    在这里插入图片描述
    但是,新建的命名空间,它里面是没有任何服务的,我们要把对应的服务分配给我们的namespaces,我们就得记住我们对应的namespaces的id,比如我的id是: bf0be804-a669-449d-bb10-40aadd8b0a8e。

    那么,我要将某个服务的实例配置到test这个命名空间下,我就在他的配置信息中添加如下配置:

    spring:
      cloud:
        nacos:
          discovery:
            namespace: bf0be804-a669-449d-bb10-40aadd8b0a8e #命名空间的ID
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们可以把上面的配置信息配置到order服务下,然后重启order服务,再去看test这个命名空间下的服务情况:
    在这里插入图片描述
    此时,我们再访问order服务,由于user服务跟他不在同一个命名空间下,他将因为请求不到数据而报500错误。
    在这里插入图片描述

    4.5 Nacos和Eureka的区别

    Nacos和Eureka的共同点大概如下图:

    1、服务的提供者向nacos/Eureka 注册中心进行服务信息的注册

    2、服务的消费者并非每次需要服务都向注册中心拉取服务列表,而是定时(每隔30秒)发送请求获取我们的服务列表并进行缓存。

    3、当消费者需要远程调用提供者的接口的时候,就会在我们的缓存中向分配到的提供者发送请求进行远程调用。

    在这里插入图片描述
    以上是Eureka和Nacos相同的地方,不同的点如下:

    1. nacos对服务提供者有临时实例和非临时实例的区分,默认是临时实例。当提供者是临时实例的时候,他跟Eureka一样,服务需要定时向nacos/Eureka 注册中心发送请求(做心跳检测),告诉注册中心,我还能用。如果哪天临时实例宕机了,那么nacos会直接把他从服务列表中剔除

      而非临时实例就不一样了,非临时实例是nacos特有的,他是由nacos主动询问是否还活着,如果哪天非临时实例宕机了,nacos 也不会将他从服务列表中剔除,而是标识他处于不健康的状态,直到他重新开机。

    2. nacos对服务消费者多了一个主动推送变更消息的功能,即,一旦nacos发现有服务提供者,他会立刻自动发消息给消费者,让他及时更新服务列表缓存,避免了Eureka定时拉取的30秒间隔内提供者宕机导致的异常。

    在这里插入图片描述
    要想设置实例为非临时实例,使用以下配置信息:

    spring:
      cloud:
        nacos:
          discovery:
            ephemeral: false  #非临时实例
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.6 Nacos配置管理

    Nacos除了可以做注册中心,同样可以做配置管理来使用。

    当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。我们需要一种统一配置管理方案,可以集中管理所有实例的配置。

    Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新。

    配置步骤如下:

    (1)打开我们的Nacos,点击左侧的配置管理 》 配置列表,然后点击右侧加号,添加配置文件
    在这里插入图片描述
    (2)书写我们的配置文件名和需要热更新的配置信息,我们的DataID也就是我们的文件名,一般取名的规则是服务名+环境 +后缀(.yaml)。
    在这里插入图片描述
    举个实例:

    针对我们开发环境的user服务,我们给他取名叫 user-dev.yaml,配置格式为YAML,而生产环境需要输出的日志格式是年月日 时分秒。那么配置信息就如下所示:
    在这里插入图片描述

    注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。

    进行Nacos配置管理前,我们获取配置的步骤如下:

    1. 项目启动
    2. 读取本地配置文件 application.yaml
    3. 创建spring容器
    4. 加载bean

    进行Nacos配置管理后,我们获取配置的步骤如下:

    1. 项目启动
    2. 读取nacos中的配置文件
    3. 读取本地配置文件 application.yaml
    4. 创建spring容器
    5. 加载bean

    但是,问题来了,要想读取nacos中的配置文件信息,我们首先需要知道我们的nacos的地址,而nacos的地址被我们放在了本地配置文件中,这不就坏起来了吗?这怎么玩?这个时候,我们就需要用到我们的bootstrap.yaml文件了。项目启动后,我们会首先读取这个bootstrap.yaml文件,然后再去读取nacos中的配置文件,因此,我们只需要将nacos的配置信息放到bootstrap.yaml文件中就可以啦。

    因此,为了拉取Nacos中的配置管理信息,我们需要以下几个步骤:

    步骤一、在需要进行热更新的服务中导入nacos的配置管理依赖

    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    步骤二、在服务中新建bootstrap.yaml文件,这个文件是引导文件,优先级高级application.yaml。这里需要注意一点哈,spring.appliction.name的值 + spring.profiles.active的值 + .yaml 等于我们的配置管理的DataID。也就是上面配置的 user-dev.yaml。

    spring:
      application:
        name: user #服务名称
      profiles:
        active: dev #开发环境(dev)
      cloud:
        nacos:
          server-addr: localhost:8848 #Nacos地址
          config:
            file-extension: yaml #配置管理文件的文件后缀
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    鉴于之前的项目,我们把nacos的配置信息写在application.yaml中了,我们还需要把对应的信息删掉,user服务的application.yaml文件最终如下:

    #端口号
    server:
      port: 8081
    
    #数据源
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/user?useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
    #  #服务名称
    #  application:
    #    name: user
    #  cloud:
    #    nacos:
    #      server-addr: localhost:8848 #nacos地址
    #      discovery:
    #        cluster-name: SZ  #集群名称
    #        ephemeral: false  #非临时实例
    
    #mybatis
    mybatis:
      type-aliases-package: com.example.user.pojo
      configuration:
        map-underscore-to-camel-case: true
    
    #日志
    logging:
      level:
        cn.itcast: debug
      pattern:
        dateformat: MM-dd HH:mm:ss:SSS
    
    #eureka:
    #  client:
    #    service-url:
    #      defaultZone: http://127.0.0.1:8090/eureka
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    上面几个步骤,只是让我们的配置管理信息能够被服务器成功拉取下来,但是,还不能实现配置的热更新。要想实现配置的热更新,有以下两种方法:

    方法一、 在@Value注入的变量所在的类上添加注解@RefreshScope

    @RestController
    @Slf4j
    @RefreshScope
    public class UserController {
    
        @Value("{pattern.dateformat}")
        private String dateformat;
        ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果想要查看/验证我们的信息是否成功拉取,可以写个Get请求如下:

    @RestController
    @Slf4j
    @RefreshScope
    public class UserController {
    
        @Value("{pattern.dateformat}")
        private String dateformat;
    
        @GetMapping("/getDate")
        public String getDate(){
            return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    方法二、使用@ConfigurationProperties注解

    @Data
    @Component
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果想要查看/验证我们的信息是否成功拉取,可以写个Get请求如下:

    @RestController
    @Slf4j
    public class UserController {
        @Resource
        private PatternProperties properties;
    
        @GetMapping("/getDate")
        public String getDate(){
            return LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对于部分适用于我们所有环境的配置信息,我们也可以做多环境共享配置。

    微服务启动的时候,会从nacos中读取多个配置文件:

    • [spring.application.name]-[spring.profiles.active].yaml,例如user-dev.yaml
    • [spring.application.name].yaml,例如user.yaml

    做个测试,我们再添加一个配置:
    在这里插入图片描述
    然后我们修改PatternProperties类如下:

    package com.example.user.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    @Data
    @Component
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
        private String envShareValue;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    之后我们写一个prop的控制器方法中把这两个值都输出来看一下:

    @GetMapping("prop")
    public PatternProperties properties(){
        return properties;
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    注意,多种配置环境的优先级为:

    服务名-环境名.yaml > 服务名.yaml > 本地配置(application.yaml)

  • 相关阅读:
    java计算机毕业设计汉语言类网上考试系统源码+mysql数据库+系统+LW文档+部署
    Java--Object类
    EfficientDet: Scalable and Efficient Object Detection
    Python条件语句的用法
    Django系列之Serializer的source参数使用、自定义序列化方法
    C#:实现渗透建堆算法(附完整源码)
    dubbo 设置注册到注册中心的IP地址为公网IP
    电子学会C/C++编程等级考试2022年09月(一级)真题解析
    win10字体模糊怎么办?解决方案全解析!
    第81天-红蓝对抗-AWD 监控&不死马&垃圾包&资源
  • 原文地址:https://blog.csdn.net/weixin_44741023/article/details/126088690