Nacos 基础教程

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现配置管理服务管理平台

Github地址:https://github.com/alibaba/nacos.
官网地址:https://nacos.io/zh-cn/docs.

一、背景

传统的单体的服务业务模块之间直接内部通过service接口调用,随着业务规模的发展,各业务模块内部的需求粒度更精细、更独立、更深入,此时如果所有业务代码仍然集成在同一个项目里,则造成代码臃肿、难维护、甚至启动加载时间也会超慢。

为此需要对项目做业务拆分,将原本的项目按业务模块进行细化拆分,分为多个独立的微服务。这些独立的微服务可以有自己的IP和端口,可以集群部署,可以再次甚至多次细化拆分。

拆分之后的各服务之间是单独的进程,服务之间需要交流,则需要网络传输的方式进行数据交互和信息交换,因此产生了传统的 RPC 远程调用框架。

在传统的 RPC 远程调用框架中,管理每个服务与服务之间依赖关系比较复杂、管理比较复杂。

我们需要记录对方服务的IP和端口,集群模式下还需要设置多个IP,如果调用的服务很多,单纯的维护这些信息就会造成配置问题件很繁琐。而且无法动态应对服务地址的变更,或服务机器量的变更。

二、服务发现

所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册,在此背景下,服务注册中心就应用而生了。

服务发现是微服务架构体系中最关键的组件之一。如果尝试着用手动的方式来给每一个客户端来配置所有服务提供者的服务列表是一件非常困难的事,而且也不利于 服务的动态扩缩容。Nacos Discovery Starter 可以帮助您将服务自动注册到 Nacos 服务端并且能够动态感知和刷新某个服务实例的服务列表。除此之外,Nacos Discovery Starter 也将服务实例自身的一些元数据信息-例如 host,port, 健康检查URL,主页等-注册到 Nacos 。

共涉及到以下 3 个角色:

  1. 服务注册中心(Register Service):它是一个 Nacos Server,可以为服务提供者和服务消费者提供服务注册和发现功能。
  2. 服务提供者(Provider Service):它是一个 Nacos Client,用于对外服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现和调用。
  3. 服务消费者(Consumer Service):它是一个 Nacos Client,用于消费服务。它可以从服务注册中心获取服务列表,调用所需的服务。

Nacos 实现服务注册与发现的流程如下:

  1. 服务提供者 Nacos Client 启动时,会把服务以服务名(spring.application.name)的方式注册到服务注册中心(Nacos Server);
  2. 服务消费者 Nacos Client 启动时,也会将自己的服务注册到服务注册中心;
  3. 服务消费者在注册服务的同时,它还会从服务注册中心获取一份服务注册列表信息,该列表中包含了所有注册到服务注册中心上的服务的信息(包括服务提供者和自身的信息);
  4. 在获取了服务提供者的信息后,服务消费者通过 HTTP 或消息中间件远程调用服务提供者提供的服务。

1.主流注册中心的比较

目前主流的服务注册中心主要包括Eureka、Consul、ZooKeeper、Nacos等。

选择 AP 还是 CP ?
服务注册中心到底选用 CP 模型还是 AP 模型,还是要依照业务场景进行决定,如果对数据一致性要求较高,且可以容忍一定时间的不可用,就选用 CP 模型。反之,如果可以容忍一定时间的数据不一致性,但不能容忍不可用现象发生,则要选用 AP 模型。
道理是这样的,但是目前市场上大部分的服务还是选择AP的较多,为什么?
对于服务发现来说,针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也并不会造成灾难性的后果。因为对于服务消费者来说,能消费才是最重要的,消费者虽然拿到可能不正确的服务实例信息后尝试消费一下,也要胜过因为无法获取实例信息而不去消费,导致系统异常要好。从这一点上来说,分布式服务注册中心AP模式要更优于CP模式。这也是为什么越来越多的人抛弃Zookeeper的原因所在。

对于Nacos 而言,如果注册 Nacos 的 client 节点注册时 ephemeral=true,那么 Nacos 集群对这个 client 节点的效果就是 AP,采用 distro 协议实现;而注册Nacos 的 client 节点注册时ephemeral=false,那么 Nacos 集群对这个节点的效果就是 CP 的,采用 Raft 协议实现。根据 client 注册时的属性,AP、CP同时混合存在,只是对不同的 client 节点效果不同。Nacos 可以很好的解决不同场景的业务需求。

# false为永久实例,true表示临时实例开启,注册为临时实例,默认是true
spring.cloud.nacos.discovery.ephemeral=true

2. 选择Nacos的理由

  • 简单易⽤:简单的数据模型,标准的 restfulAPI,易用的控制台,丰富的使用文档。
  • 高可用:99.9% 高可用,同时支持CP和AP,历经阿里巴巴 10 年生产验证的内部产品,支持具有数百万服务的大规模场景。
  • 产品用户多: 社区活跃,服务于众多互联网级公司客户。
  • 实时高性能:数据变更毫秒级推送生效;(1w 级,SLA 承诺 1w 实例上下线 1s,99.9% 推送完成;10w级,SLA 承诺 1w 实例上下线 3s,99.9% 推送完成;100w 级别,SLA 承诺 1w 实例上下线 9s 99.9% 推送完成。)
  • 生态丰富:Nacos 几乎支持所有主流语言,也对微服务生态活跃的技术做了无缝的支持,是 Java 微服务生态最佳解决方案。

3.Nacos 概念

Nacos 引入了一些基本的概念,系统性的了解一下这些概念可以帮助您更好的理解和正确的使用 Nacos 产品。

1.Namespace

Namespace 的设计就是用来进行资源隔离的,用于进行租户粒度和多环境的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。

从单个租户的角度来看,我们要配置多套环境的配置,可以根据不同的环境来创建 Namespace,例如开发测试环境、测试环境、生产环境的资源等。命名方式一般是:项目名+环境,如mall-dev,可以在nacos的管理页进行创建。

从多租户的角度来看,每个租户都可以有自己的命名空间。我们可以为每个用户创建一个命名空间,并给用户分配对应的权限,每个租户也可以有自己的多环境配置。

创建完成之后会生成一个唯一的UUID的字符串,这个字符串就可以在项目中nacos的地方配置使用。

2.Data ID
Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。

在微服务中,每一个项目下有若干个服务,每个 DataID 是一个工程的主配置文件,类似于springboot项目中多application.properties的配置文件。

3.Group
通过一个有意义的字符串(如 Pay 或 Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。

其实主要用来代表项目。如果只有单一的项目,没必要麻烦,默认的即可。如果有多个项目用一个nacos环境,可以用项目作为Group值来区分相同的配置文件。

Namespace(命名空间):用来隔离区分环境或租户。
Data ID(配置集):用来区分多配置值,如redis、Mq、db等;
Group(分组):用来区分项目,将业务相关度比较高的放到一组里面,例如订单和支付。

4.自定义配置规范

1. Namespace: 默认public,命名规则:项目名为开头,如果有租户区分则再拼接租户标识, 最后是环境隔离,之间通过-分割,字母小写。

规则:
${prefix}-${tenant}-${spring.profiles.active}

示例:

2. Group: 默认DEFAULT_GROUP,命名规则:以项目或业务名为开头,以GROUP结尾,通过_链接,字母大写。

规则:
${prefix}_GROUP

示例:

3. DataId: 命名规则:通用的配置以common开头,非通用的以项目名开头,后续加以配置类别,最后以扩展名结尾,之间通过-链接,字母小写。

规则:

  • 通用:common-${function}.${file-extension}
  • 非通用:${application-name}-${function}.${file-extension}

示例:

4. Nacos 注册中心集成 springcloud

mven依赖:

<!--nacos 注册中心-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

注意:版本 2.1.x.RELEASE 对应的是 Spring Boot 2.1.x 版本。版本 2.0.x.RELEASE 对应的是 Spring Boot 2.0.x 版本,版本 1.5.x.RELEASE 对应的是 Spring Boot 1.5.x 版本,更多版本对应关系参考:版本说明 Wiki

bootstrap.yaml

spring:
  application:
    name: service-a
  cloud:
    nacos:
      discovery:
        register-enabled: true
        server-addr: 172.30.13.74:8801,172.30.13.74:8802,172.30.13.74:8803
        namespace: 9faec1a8-3a76-4158-af81-963055755e2e

配置说明

| 配置项 |Key |默认值 |说明 |
| -------- | --------| -- |
| 服务端地址 |spring.cloud.nacos.discovery.server-addr|无|Nacos Server 启动监听的ip地址和端口|
|服务名|spring.cloud.nacos.discovery.service|${spring.application.name}|给当前的服务命名|
|服务分组|spring.cloud.nacos.discovery.group|DEFAULT_GROUP|设置服务所处的分组|
|服务分组|spring.cloud.nacos.discovery.namespace|public|设置服务所处的命名空间|
|是否集成Ribbon|ribbon.nacos.enabled|true|一般都设置成true即可|

开启注册功能

通过 Spring Cloud 原生注解 @EnableDiscoveryClient 开启服务注册发现功能

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

三、配置管理

Nacos除了可以作为服务发现的注册中心,还可以作为配置中心。

1.springCloud 集成 Nacos

maven依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>${latest.version}</version>
</dependency>

bootstrap.yaml

spring:
  application:
    name: cashier-user
  cloud:
    nacos:
      config:
        server-addr: 172.30.13.74:8845,172.30.13.74:8847,172.30.13.74:8849
#        prefix: cashier
        file-extension: yaml
        namespace: 9faec1a8-3a76-4158-af81-963055755e2e
        # 用于共享的配置文件
        shared-configs:
          - data-id: common-redis.yaml
            group: cashier-group
          - data-id: common-rocketmq.yaml
            group: cashier-group
          - data-id: common-mybatisplus.yaml
            group: cashier-group

配置说明

| 配置项 |Key |默认值 |说明 |
| --------| -------- | --- |
| 服务端地址 |spring.cloud.nacos.config.server-addr|无|Nacos Server 启动监听的ip地址和端口|
|服务名|spring.cloud.nacos.config.file-extension|无|配置文件扩展名|
|服务分组|spring.cloud.nacos.config.namespace|public|设置服务所处的命名空间|
|服务分组|spring.cloud.nacos.config.shared-configs|无|设置共享配置|

读取规则

在Spring Cloud Nacos 中,Nacos是根据什么规则找到对应配置文件的?
dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}
  • prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
  • spring.profiles.active 即为当前环境对应的 profile。 当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
  • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。

假如 spring.application.name=nacos-demo, spring.profiles.active=devfile-extension=yaml,则配置优先级高到低顺序为:nacos-demo-dev.yaml -> nacos-demo.yaml -> nacos-demo

2. 加载多个配置

日常开发项目中经常会遇到多配置的场景,如application-redis.properties、application-mq.properties、application-db.properties、监控配置等等,而且有些配置文件有的各项目可以共享,有的是独有的,那么这些怎么设置呢?

Nacos提供了共享配置(shared-configs)扩展配(extension-config),来解决这种问题。

每个配置中包含三个参数:data-id、group,refresh;前两个不再赘述,refresh参数控制这个配置文件中的内容是否支持自动刷新,默认情况下,只有默认加载的配置才会自动刷新,对于这些扩展的配置加载内容需要配置该设置时候才会实现自动刷新。

如果没有明确配置,默认情况下所有共享配置和扩展配置都不支持动态刷新。

共享配置(shared-configs)

Nacos在配置路径spring.cloud.nacos.config.shared-configs下,允许我们指定⼀个或多个共享配置。

...
# 用于共享的配置文件
shared-configs:
  - data-id: common-redis.yaml
    group: cashier-group
    refresh: true
  - data-id: common-rocketmq.yaml
    group: cashier-group
    refresh: true
  - data-id: common-mybatisplus.yaml
    group: cashier-group
    refresh: true

扩展配(extension-config)

Nacos在配置路径spring.cloud.nacos.config.extension-config下,允许我们指定⼀个或多个额外配置。

...
# 用于共享的配置文件
extension-configs:
  - data-id: actuator.yaml
    group: cashier-group
    # 让扩展配置刷新
    refresh: true
  - data-id: log.yaml
    group: cashier-group
    refresh: true

关于优先级

配置文件既可以存在于本地项目中,也可以在Nacos中,那么对于重复的配置项,优先级顺序是怎样的呢?

首先在默认情况下和本地配置相比,存在如下优先级:远程配置 > 本地配置 > java代码配置。当需要本地配置优先时,可以通过如下方式限制远程配置的优先级。

spring:
  cloud:
    config:
      // 允许nacos被本地文件覆盖
      allow-override: true
      // nacos不覆盖任何本地文件
      override-none: true
      // nacos 覆盖系统属性。注意本地配置文件不是系统属性
      override-system-properties: true

以上是本地配置和 Nacos 配置的优先级比较,而且需要在远程配置中添加,否则不生效,通过上文的了解,我们在使用Nacos 配置的时候,Nacos 本身也主要有以下三类配置:

  1. 通过spring.cloud.nacos.config.shared-configs定义的共享配置。
  2. 通过spring.cloud.nacos.config.extension-configs定义的加载配置。
  3. 通过内部规则(spring.cloud.nacos.config.prefixspring.cloud.nacos.config.file-extensionspring.cloud.nacos.config.group 这几个参数)拼接出来的配置。

当我们加载如上多个配置的时候,如果存在相同的 key 时,这些配置加载的优先级关系是怎么样的呢?

1、上述两类配置都是数组,对同种配置,数组元素对应的下标越⼤,优先级越⾼。也就是排在后⾯的相同配置,将覆盖排在前⾯的同名配置。

  • 同为扩展配置,存在如下优先级关系:extension-configs[3] > extension-configs[2] > extension-configs[1] > extension-configs[0]。

  • 同为共享配置,存在如下优先级关系:shared-configs[3] > shared-configs[2] > shared-configs[1] > shared-configs[0]。

2、不同种类配置之间,优先级按顺序如下:主配置 > 扩展配置(extension-configs) > 共享配置(shared-configs)

读取配置

在 nacos 中设置了属性对应的配置值,如何在应用项目中读取呢?

# 免验签的路径
exclude-paths: /user/login,/login
# 验签开关
sign-switch: false
# 网关链接有效时间, 1000 * 60 * 60 * 24
link_expired_time: 86400000

其实读取的方式很简单,如果你的dataId设置的正确,直接通过spring的 @Value注解就可以获取到对应的配置值。

@Value("${exclude-paths}")
private String excludePaths;

@Value("${sign-switch}")
private boolean signSwitch;

@Value("${link_expired_time}")
private Long linkExpiredTime;

关于动态刷新

我们使用Nacos主要是期望能通过它实现动态修改配置而不需要重启服务,即配置热更新,Nacos 通过 @RefreshScope注解来实现动态属性值刷新,这是springcloud所属的一个注解,通过注解可以知道,该注解作用于类和方法上。

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {

	/**
	 * @see Scope#proxyMode()
	 * @return proxy mode
	 */
	ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;

}

@RefreshScope@Value 必须一起出现,不然项目控制台打印有变更日志,但是请求结果却一直没有改变。

  • @RefreshScope 添加到类上,就是说明在项目运行过程中,如果远程配置文件有做修改,修改的信息在@RefreshScope添加的类中有使用,就会将原有的实例注销,在重新创建一个新的实例运行。这样就能保证在项目不重启的情况下读取到最新的修改信息。
  • 如果修改的配置信息在没有添加@RefreshScope的类中使用,这个类的实例就不会注销,所以不管怎么修改,没有加@RefreshScope的类请求结果一直都会是项目运行时加载的旧数据。

这种用法是最简单的,也符合我们常用的 spring 开发习惯,但是它有需要注意的点,使用不当会造成读取不到动态更新的配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章