SpringCloud-Alibaba的Nacos究竟有多好用?

1,747 阅读10分钟

Nacos是什么?

官方是这么说的 🔈

  1. nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
  2. 服务(Service)是Nacos世界的一等公民。

官网:nacos.io/zh-cn/

怎么去理解这两句话呢?也就是说Nacos不仅提供了服务注册与发现功能,还提供了配置管理的功能,同时还提供了可视化的管理平台。而Nacos又是围绕着Service转的。

如果大家查看源码,会发现Nacos的核心API中定义了两个接口NamingService和ConfigService。服务注册与发现围绕着NamingService展开,而配置管理则围绕着ConfigService展开。

  • 概括:Nacos就是注册中心+配置中心的组合

  • 等价:Nacos = Eureka+Config+Bus

Nacos的4个核心特性 👇

服务发现和服务健康监测

  • Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务,Nacos还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。

动态配置服务

  • 动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新部署应用程序,这使配置的更改更加高效和灵活。

动态DNS服务

  • Nacos提供基于DNS协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端点,让三方应用方便的查阅及发现。

服务和元数据管理

  • Nacos能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述,生命周期,服务的静态依赖分析,服务的健康状态,服务的流量管理,路由及安全策略。

nacos config对比springcloud config有何优势? 👇

  • springcloud config大部分场景结合git 使用, 动态变更还需要依赖Spring Cloud Bus 消息总线来通过所有的客户端变化。

  • springcloud config不提供可视化界面。

  • nacos config使用长连接更新配置, 一旦配置有变动后,通知Provider的过程非常的迅速, 从速度上秒杀springcloud原来的config几条街。

注册中心有了Eureka ,为何还要用Nacos? 👇

  • eureka 2.0闭源码了。

  • 从官网来看nacos 的注册的实例数是大于eureka的。

  • 因为nacos使用的raft协议,nacos集群的一致性要远大于eureka集群。


raft协议

分布式一致性协议 Raft,自 2013 年论文发表,之后就受到了技术领域的热捧,与其他的分布式一致性算法比,Raft 相对比较简单并且易于实现,这也是 Raft 能异军突起的主要因素。

在这里插入图片描述

Raft 协议强依赖 Leader 节点来确保集群数据一致性。即 client 发送过来的数据均先到达 Leader 节点,Leader 接收到数据后,先将数据标记为 uncommitted 状态,随后 Leader 开始向所有 Follower 复制数据并等待响应,在获得集群中大于 N/2 个 Follower 的已成功接收数据完毕的响应后,Leader 将数据的状态标记为 committed,随后向 client 发送数据已接收确认,在向 client 发送出已数据接收后,再向所有 Follower 节点发送通知表明该数据状态为committed。


下载安装Nacos

  • 下载前确保本地Java8+Maven环境已经ok

下载地址:github.com/alibaba/nac…

在这里插入图片描述

解压安装包,解压完成后直接运行bin目录下的startup.cmd

在这里插入图片描述在这里插入图片描述

运行成功后直接访问 http://localhost:8848/nacos

  • 默认账号密码都是 nacos

在这里插入图片描述 在这里插入图片描述

如需使用Docker下载安装Nacos并完成持久化配置点击后方链接进行跳转 👉 Docker下载安装Nacos并完成持久化配置


Nacos领域模型

由于项目应用环境的复杂度,同时考虑到各类数据的有效存储管理,在Nacos中对于数据的归类存储提供了不同的模型结构。

在这里插入图片描述

  • Namespace(命名空间):对不同的环境进⾏隔离,⽐如隔离开发环境、测试环境和⽣产环境。
  • Group(分组):,将若⼲个服务或者若⼲个配置集归为⼀组,通常习惯⼀个系统归为⼀个组。推荐命名格式:产品名称+分组名称
  • Service(服务):某⼀个服务,例如会员微服务。

在下图的分级存储模型可以看到,在服务级别,保存了健康检查开关、元数据、路由机制、保护阈值等设置,而集群保存了健康检查模式、元数据、同步机制等数据,实例保存了该实例的ip、端口、权重、健康检查状态、下线状态、元数据、响应时间。在这里插入图片描述

  • Cluster(集群):集群是一个逻辑概念,可以区分不同的服务节点所处的网络环境。
  • Instance(实例):保存具体的微服务注册数据,每一个服务节点对应一个实例数据。
  • DataId(配置数据ID):自定义的配置数据集推荐命名格式:包名称.类名称(小写字母)

可以在nacos控制台看到与之对应的界面

在这里插入图片描述

如果还无法理解,我们可以直接从代码层面来看看Namespace、Group和Service是如何存储的。

/** 
 * Map(namespace, Map(group::serviceName, Service)). 
 */ 
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();

Nacos服务注册表结构为 Map。这个双层Map的key分别是namespace和group::serviceName,Nacos基于namespace的设计是为了做多环境以及多租户数据(配置和服务)隔离的。如果用户有多套环境(开发、测试、生产等环境),则可以分别建三个不同的namespace。

在此我们先忽略掉一对多的情况,假如只有一个命名空间它的整个层级包含关系为Namespace包含多个Group、Group可包含多个Service、Service可包含多个Cluster、Cluster中包含Instance集合。

// ServiceManager类,Map(namespace, Map(group::serviceName, Service)) 
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>(); 
     
// Service类,Map(cluster,Cluster) 
private Map<String, Cluster> clusterMap = new HashMap<>(); 
     
// Cluster类 
private Set<Instance> persistentInstances = new HashSet<>(); 
private Set<Instance> ephemeralInstances = new HashSet<>(); 
     
// Instance类 
private String instanceId; 
private String ip; 
private int port; 
private double weight = 1.0D; 

其中,实例又分为临时实例和持久化实例。它们的区别关键是健康检查的方式。临时实例使用客户端上报模式,而持久化实例使用服务端反向探测模式。

临时实例需要能够自动摘除不健康实例,而且无需持久化存储实例。持久化实例使用服务端探测的健康检查方式,因为客户端不会上报心跳,自然就不能去自动摘除下线的实例。


Nacos作为注册中心

注册中心可以说是微服务架构中的通讯录,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。

注册中心主要有三部分组成服务注册中心、服务提供者、服务消费者

在这里插入图片描述

Nacos注册中心实例剔除策略

服务注册的策略的是每5秒向nacos server发送一次心跳,心跳带上了服务名,服务ip,服务端口等信息。同时 nacos server也会向client 主动发起健康检查,支持tcp/http检查。如果15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例。

Nacos的Server与Client

Nacos注册中心分为Server与Client,Nacos提供SDK和openApi,如果没有SDK也可以根据openApi手动写服务注册与发现和配置拉取的逻辑。

Server采用Java编写,基于Spring Boot框架,为Client提供注册发现服务与配置服务。Client支持包含了目前已知的Nacos多语言客户端及Spring生态的相关客户端。Client与微服务嵌套在一起。

Nacos的DNS实现依赖了CoreDNS,其项目为nacos-coredns-plugin。该插件提供了基于CoreDNS的DNS-F客户端,开发语言为go。

在这里插入图片描述


注册中心使用方法

本文演示的nacos版本为1.1.3,springcloud版本为2.1.0.RELEASE,springcloud-alibaba采用的版本为Greenwich.SR3,springboot对应版本为2.1.8.RELEASE。

1.添加相关依赖

nacos的Maven依赖

<!--nacos 服务注册/发现-->
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>

要想引入上方依赖,首先需要确定本项目是个boot项目,还需先引入SpringCloud-Alibaba依赖。如果实在不会修改可参考下方pom文件。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
	<!--在下方填上自已的gva坐标-->
	<groupId>com.xxx</groupId>
    <artifactId>xxx-xxx</artifactId>
    <version>1.0-SNAPSHOT</version>


    <!--版本控制-->
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>

    <dependencies>
        <!--nacos 服务注册/发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.编写配置文件

声明需注册到,注册中心的地址,以及服务名称等

spring:
  cloud:
    nacos:
      discovery:
        server-addr: xx.xxx.xxx.xx:8848 #注册中心地址
  application:
    name: lgmall-coupon #服务名称
server:
  port: 8010 #端口号

3.编写启动类

使用@EnableDiscoveryClient注解在我们启动类上开启服务注册与发现

@EnableDiscoveryClient

在这里插入图片描述

4.测试

成功启动后我们打开注册中心控制台,可以查看到注册成功的微服务。

在这里插入图片描述


Nacos作为配置中心

在微服务架构中,当系统从一个单体应用拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移(分割),这样配置就分散了,不仅如此,分散中还包含着冗余,如下图

在这里插入图片描述 为了解决这种情况,就诞生了配置中心。配置中心会将配置从各个应用中剥离出来,对配置进行统一管理。使应用自身不需要自已去管理配置。

Nacos配置中心架构

配置中心本身并不复杂,前提是你先将 CAP 的取舍问题晾在一边的话。配置中心最基础的功能就是存储一个键值对,用户发布一个配置(configKey),然后客户端获取这个配置项(configValue);进阶的功能就是当某个配置项发生变更时,将变更告知客户端刷新旧值。

下方的架构图,简要描述了一个配置中心的大致架构,用户可以通过管理平台发布配置,通过 HTTP 调用将配置注册到服务端,服务端将之保存在 MySQL 等持久化存储引擎中;用户通过客户端 SDK 访问服务端的配置,同时建立 HTTP 的长轮询监听配置项变更,同时为了减轻服务端压力和保证容灾特性,配置项拉取到客户端之后会保存一份快照在本地文件中,SDK 优先读取文件里的内容。

在这里插入图片描述

配置中心使用方法

配置中心与注册中心所有的版本都是一致的。

1.添加相关依赖

引入 Nacos Config Starter依赖。

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

2.修改配置文件

创建bootstrap.properties配置文件,并配置nacos config元数据

  • bootstrap.properties 比yml文件优先加载
spring.application.name=lgmall-coupon
spring.cloud.nacos.config.server-addr=xx.xxx.xxx.xx:xxxx

在这里插入图片描述

3. 在控制台添加配置规则

在配置中心添加一个叫 数据集(Data Id) lgmall-coupon.properties。

  • 默认规则 应用名.properties

在这里插入图片描述

4.编写java代码

通过@Value读取远程配置,另外为保证动态刷新配置还要加上@RefreshScope注解

@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

    @Value("${user.ponName}")
    private String name;


    @GetMapping("/test")
    public R test(){
        return R.ok().put("name",name);
    }
 }

5.测试

成功启动后,我们调用接口查看最终结果,发现成功读取到了配置中心的值

在这里插入图片描述


实战中如何使用Nacos配置中心

  1. 创建命名空间,微服务项目中每个环境创建不同的命名空间,使用分组区分不同的微服务

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

在这里插入图片描述

  1. 创建配置集,以下方项目为例,我们需要对除common外5个微服务进行分组,并创建其配置文件。这里我们以test测试环境为例

在这里插入图片描述

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 创建好后整体效果如下

在这里插入图片描述

  1. 读取多配置集并动态刷新,微服务任何配置信息都可以放在配置中心中,只需要在bootstrop.properties中说明加载哪些配置文件即可,以前springboot任何从配置文件中获取值的方法(如:@Value @ConfigurationProerties)都能使用,配置中心有的优先读取配置中心的。
# bootstrap.properites 比yml文件优先加载
spring.application.name=lgmall-coupon

spring.cloud.nacos.config.server-addr=xx.xxx.xxx.xx:8848

#使用哪个命名空间下的配置,注意需要写命名空间的唯一id不能写名字
spring.cloud.nacos.config.namespace=ef375233-21be-646b-b955-6f3e0d855951

#数据源相关配置
spring.cloud.nacos.config.ext-config[0].data-id=datasource.yaml
spring.cloud.nacos.config.ext-config[0].group=coupon
spring.cloud.nacos.config.ext-config[0].refresh=true

#mybatis相关配置
spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yaml
spring.cloud.nacos.config.ext-config[1].group=coupon
spring.cloud.nacos.config.ext-config[1].refresh=true

#nacos相关配置
spring.cloud.nacos.config.ext-config[2].data-id=nacos.yaml
spring.cloud.nacos.config.ext-config[2].group=coupon
spring.cloud.nacos.config.ext-config[2].refresh=true

#其它配置
spring.cloud.nacos.config.ext-config[3].data-id=other.yaml
spring.cloud.nacos.config.ext-config[3].group=coupon
spring.cloud.nacos.config.ext-config[3].refresh=true

data-id代表具体哪个配置,group代表读取哪个组,refresh=true代表动态刷新,可对应下图查看

在这里插入图片描述

  1. 启动并测试

在这里插入图片描述

通过上方日志我们可以发现,启动成功后他会优先读取lgmall-coupon.properties配置文件,我们没有配置该配置文件,它就会继续读取datasource.yamlother.yamlnacos.yamlmybatis.yaml

Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='lgmall-coupon.properties'}, NacosPropertySource {name='other.yaml'}, NacosPropertySource {name='nacos.yaml'}, NacosPropertySource {name='mybatis.yaml'}, NacosPropertySource {name='datasource.yaml'}]}

我们访问数据库发现请求成功!

在这里插入图片描述