08-服务配置中心Nacos的应用

2022-09-07 11:06:43

1.配置中心简介

1.1 背景分析

除了代码之外,软件还有一些配置信息,比如数据库的用户名和密码,还有一些我们不想写死在代码里的东西,例如像线程池大小、队列长度等运行参数,以及日志级别、算法策略等, 还有一些是软件运行环境的参数,如Java 的内存大小,应用启动的参数,包括操作系统的一些 参数配置…… 所有这些东西,我们都叫做软件配置。以前,我们把软件配置写在一个配置文件中,就像 Windows 下的 ini 文件,或是 Linux 下的 conf 文件。然而,在分布式系统下,这样的方式就变得非常不好管理,并容易出错。假如生产环境下,项目现在正在运行,此时修改了配置文件,我们需要让这些配置生效,通常的做法是不是要重启服务。但重启是不是会带来系统服务短时间的暂停,从而影响用户体验呢,还有可能会带来经济上的很大损失(例如双11重启下服务)。基于这样的背景,配置中心诞生了。

1.2 配置中心的概述

配置中心最基础的功能就是存储一个键值对,用户发布一个配置(configKey),然后客户端获取这个配置项(configValue);进阶的功能就是当某个配置项发生变更时,不停机就可以动态刷新服务内部的配置项,例如,在生产环境上我们可能把我们的日志级别调整为 error 级别,但是,在系统出问题我们希望对它 debug 的时候,我们需要动态的调整系统的行为的能力,把日志级别调整为 debug 级别。如果同时涌进来超过一亿人并发访问的时候,假如系统是扛不住的,在这个过程中我们一般会采用限流,降级。系统的限流和降级本质上来讲就是从日常的运行态切换到大促态的一个行为的动态调整,这个本身天然就是配置起到作用的一个相应的场景。

1.3 配置中心的选型

在面向分布式的微服务系统中,如何通过更高效的配置管理方式,实现微服务系统架构持续“无痛”的演进,并动态调整和控制系统的运行时态,配置中心的选型和设计起着举足轻重的作用。市场上主流配置中心有Apollo(携程开源),nacos(阿里开源),Spring Cloud Config(Spring Cloud 全家桶成员)。在下面我们选择nacos,此组件不仅提供了注册中心,还具备配置中心的功能。

2. Nacos配置快速入门

2.1 添加依赖

在已有的sca-providers项目中添加配置依赖。

<!--添加nacos配置中心依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>

2.2 修改配置文件

将项目的application.yml文件的名字修改为bootstrap.yml配置文件,因为默认bootstrap.yml的启动优先级最高。

erver:
  port: 8081
  tomcat:
    threads:
      max: 400 #最大线程数
      min-spare: 100 #核心线程数(池中最少有的线程个数)
spring:
  application:
    name: sca-providers #服务名,后续会出现在注册中心
  cloud:
    nacos:
      discovery: # 服务的注册和发现
        server-addr: localhost:8848
      config: #服务的配置
        server-addr: localhost:8848
        file-extension: yml # 配置中心文件扩展名
        namespace: 1cca4687-58bc-49a1-b526-eddcb94cd324 #命名空间,不写就默认是public
        group: DEFAULT_GROUP_51 #分组名

2.3 Nacos基本配置

打开nacos配置中心,新建配置如图所示。
1
其中,Data ID的值要与bootstrap.yml中定义的spring.application.name的值相同(服务名,假如有多个服务名,一般创建多个配置实例,不同服务对应不同的配置实例)。

2.4 Controller处理器操作

在ProviderController中添加一个获取日志级别(debug<info<warn<error)的方法。

@RefreshScope//动态刷新配置@RestControllerpublicclassProviderController{privatestaticfinalLogger log=LoggerFactory.getLogger(ProviderApplication.class);//创建了日志对象/*读取配置中心的日志级别*/@Value("${logging.level.com.cy:error}")//":"后面为默认值privateString loggingLevel;@GetMapping("/provider/doGetLevel")publicStringdoGetLevel(){//日志优先级:trace<debug<warn<info<error
            log.trace("日志跟踪信息trace!");//跟踪
            log.debug("日志调试信息debug!");//调试
            log.warn("日志警告信息warn!");//警告
            log.info("日志常规信息info!");//常规信息
            log.error("日志错误信息error!");//错误信息return"日志级别为:"+loggingLevel;}}

其中,@RefreshScope的作用是在配置中心的相关配置发生变化以后,能够及时的看到更新(底层通过重新创建Controller对象的方式,对属性进行了重新初始化),Controller编写好后,启动配置中心服务,在浏览器直接输入http://locahost:8081/provider/doGetLogLevel,检测输出结果是否为我们配置中的信息。
1
1
说明,假如对配置的信息访问不到,请检测项目配置文件的名字是否为bootstrap.yml,检查配置文件中spring.application.name的属性的值是否与配置中心的data-id名相同。

3. Nacos配置动态更新

修改Nacos的日志级别配置并重新发布。
1
刷新浏览器url,检测其配置输出。
1

4. Nacos配置管理模型

4.1 概述

Nacos配置管理模型由三部分构成,如图所示。
1
其中:

  • Namespace:命名空间,对不同的环境进行隔离,比如隔离开发环境和生产环境。
  • Group:分组,将若干个服务或者若干个配置集归为一组。
  • Service/DataId:某一个服务或者配置集,一般对应一个配置文件。

4.2 命名空间设计

Nacos中的命名空间一般用于配置隔离,这种命名空间的定义一般会按照环境(开发、生成等)进行设计和实现,我们默认创建的配置都存储到了public命名空间,如图所示。
1
创建新的开发环境并定义其配置,然后从开发环境的配置中读取配置信息。
1
命名空间创建成功以后,会在如下列表进行呈现。
1
在指定命名空间下添加配置,也可以直接在配置列表中克隆。
1
1
克隆成功以后,我们会发现在指定的命名空间中有了我们的克隆配置。
1
此时,我们修改dev命名空间中的Data Id的sca-providers配置。
1
修改项目module中的配置文件bootstarp.yml,添加如下配置。

spring:
  cloud:
    nacos:
      config: #服务的配置
        server-addr: localhost:8848
        file-extension: yml # 配置中心文件扩展名
        namespace:1cca4687-58bc-49a1-b526-eddcb94cd324 #命名空间,不写就默认是public

其中,namespace后面的字符串为命名空间的id,可直接从命名空间列表中进行拷贝。
在ProviderController类中添加属性和方法。

/*读取配置中心的日志级别*/@Value("${logging.level.com.cy:error}")//":"后面为默认值privateString loggingLevel;@GetMapping("/provider/doGetLevel")publicStringdoGetLevel(){//日志优先级:trace<debug<warn<info<error
            log.trace("日志跟踪信息trace!");//跟踪
            log.debug("日志调试信息debug!");//调试
            log.warn("日志警告信息warn!");//警告
            log.info("日志常规信息info!");//常规信息
            log.error("日志错误信息error!");//错误信息return"日志级别为:"+loggingLevel;}

重启服务,继续刷新http://localhost:8081/config/doGetLogLevel地址。
1

4.3 分组设计及实现

当我们在指定命名空间下,按环境或服务做好了配置以后,有时还需要基于服务做分组配置,例如,一个服务在不同时间节点切换不同的配置,可以在新建配置时指定分组名称。
1
配置发布以后,修改boostrap.yml配置类,在其内部指定我们刚刚创建的分组。

server:
  port:8081
spring:
  application:
    name: sca-providers #服务名,后续会出现在注册中心
  cloud:
    nacos:
      discovery: # 服务的注册和发现
        server-addr: localhost:8848
      config: #服务的配置
        server-addr: localhost:8848
        file-extension: yml # 配置中心文件扩展名
        namespace:1cca4687-58bc-49a1-b526-eddcb94cd324 #命名空间,不写就默认是public
        group: DEFAULT_GROUP_51 #分组名

在ProviderController类中添加属性和方法,用于获取和输出DEFAULT_GROUP_51配置中设置的线程数。

@Value("${server.tomcat.threads.max:500}")privateint maxThread;@GetMapping("/provider/doGetMaxThread")publicStringdoGetMaxThread(){String tName=Thread.currentThread().getName();System.out.println(tName);return"最大线程数为:"+maxThread;}

然后,重启服务,进行测试,检测内容输出。
1

4.4 共享配置设计及读取

当同一个namespace的多个配置文件中都有相同配置时,可以对这些配置进行读取,然后存储到nacos配置中心的一个或者多个指定配置文件中。哪一个微服务需要,就在服务的配置中读取即可。
第一步:在nacos中创建一个共享配置文件。
1
第二步:在指定的微服务配置文件(bootstrap.yml)中设置对共享配置文件的读取。

server:
  port:8081
spring:
  application:
    name: sca-providers #服务名,后续会出现在注册中心
  cloud:
    nacos:
      discovery: # 服务的注册和发现
        server-addr: localhost:8848
      config: #服务的配置
        server-addr: localhost:8848
        file-extension: yml # 配置中心文件扩展名
        namespace:1cca4687-58bc-49a1-b526-eddcb94cd324 #命名空间,不写就默认是public
        group: DEFAULT_GROUP #分组名
        # 共享配置
        shared-configs[0]:
                data-id: app-public-dev.yml
                refresh:true

第三步:在指定的业务类中读取和应用共享配置。

@Value("${page.pageSize:3}")privateint pageSize;@GetMapping("/provider/doGetPageSize")publicStringdoGetPageSize(){return"page size is:"+pageSize;}

第四步:启动服务进行访问测试。
1

5. 小结面试分析

  • 什么是配置中心?(存储项目配置信息的一个服务)
  • 为什么要使用配置中心?(集中管理配置信息,动态发布配置信息)
  • 市场上有哪些主流的配置中心?(Apollo,nacos,……)
  • 配置中心一般都会配置什么内容?(可能会经常变化的配置信息,例如连接池,日志、线程池、限流熔断规则)
  • 什么信息一般不会写到配置中心?(服务端口,服务名,服务的注册地址,配置中心)
  • 项目中为什么要定义bootstrap.yml文件?(此文件被读取的优先级比较高,可以在服务启动时读取配置中心的数据)
  • Nacos配置中心宕机了,我们的服务还可以读取到配置信息吗?(可以从内存,客户端获取了配置中心的配置信息以后,会将配置信息在本地内存中存储一份.)
  • 微服务应用中我们的客户端如何获取配置中心的信息?(为了考虑性能我们的服务一般首先会从内存读取配置信息,同时我们的微服务还可以定时向nacos配置中心发请求拉取(pull)更新的配置信息,但是在一定时间间隔内还可能会出现不一致的配置,所以nacos服务端而言,当配置变化时,会通知客户端然后更新客户端.)
  • 微服务应用中客户端如何感知配置中心数据变化?(当数据发生变化时,nacos找到它维护的客户端,然后通知客户端去获取更新的数据,客户端获取数据以后更新本地内存,并在下次访问资源时,刷新@Value注解描述的属性值,但是需要借助@RefreshScope注解对属性所在的类进行描述)
  • 服务启动后没有从配置中心获取我们的配置数据是什么原因?(依赖,配置文件名字bootstrap.yml,配置中心的dataId名字是否正确,分组是否正确,配置的名字是否正确,缩进关系是否正确,假如是动态发布,类上是否有@RefreshScope注解)
  • 你项目中使用的日志规范是什么?(SLF4J)
  • 你了解项目中的日志级别吗?(debug,info,error,…,可以基于日志级别控制日志的输出)

6. 重点分析

  • 配置中心的选型。(市场活跃度、稳定性、性能、易用)
  • Nacos配置中心基本应用。(新建,修改、删除配置以后,在Nacos客户端应用配置)
  • 配置管理模型应用。(namespace,group,service/dataId)
  • Nacos配置变更的动态感知。(底层原理分析)

7. FAQ分析

  • 为什么需要配置中心?(动态管理发布配置,无需重启服务,更好保证服务的可用)
  • 配置中一般要配置什么内容?(经常变化的配置数据-日志级别,线程池、连接池、…)
  • 市面上有哪些主流配置中心?(Nacos,….)
  • 配置中心选型时要重点考虑哪些因素?(市场活跃度、稳定性、性能、易用)
  • Nacos客户端(微服务业务)如何动态感知配置中心数据变化的?(nacos2.0之前nacos客户端采用长轮询机制拉取nacos服务的配置信息,pull(每隔30秒)+“push(是在服务端的配置信息变更以后,通知服务端中处于等待状态的客户端队列中的客户端对象,并更新客户端对应的响应数据,然后返回响应)”)
  • Nacos配置管理模型是怎样的?(命名空间-namespace,分组-group,服务实例-dataId)
  • 作者:XQ_898878888
  • 原文链接:https://blog.csdn.net/XQ_898878888/article/details/119219722
    更新时间:2022-09-07 11:06:43