『Nacos』 入门教程

前言

本文为 Nacos 平台快速入门教程,本文将会使用通俗易懂 的语言手把手带您了解、使用 Nacos 平台,适合未接触过 Nacos 的初学者

官方手册:Nacos | Nacos

官方仓库:alibaba/nacos
版本:2.X

本文示例代码仓库:ReturnTmp/nacos-demo (github.com)

介绍

Nacos 阿里巴巴推出来的开源项目 ,是更易于构建云原生应用动态服务发现、配置管理和服务管理平台

Nacos 致力于发现、配置和管理微服务,并提供简单易用的特性集,能够快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 更敏捷和容易地构建、交付和管理微服务平台,构建以"服务"为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施

下面将会对比常用注册中心和配置中心,并且向您介绍注册中心和配置中心的概念

注:如果您只想要快速开始,可以直接跳转到 快速开始 章节,跳过下面繁琐的概念

注册中心

注册中心主要分为三种角色:

  • 服务提供者(RPC Server):在启动时,向 Registry 注册自身服务,并向 Registry 定期发送心跳汇报存活状态。
  • 服务消费者(RPC Client):在启动时,向 Registry 订阅服务,把 Registry 返回的服务节点列表缓存在本地内存中,并与 RPC Sever 建立连接。
  • 服务注册中心(Registry):用于保存 RPC Server 的注册信息,当 RPC Server 节点发生变更时,Registry 会同步变更,RPC Client 感知后会刷新本地 内存中缓存的服务节点列表。

最后,RPC Client 从本地缓存的服务节点列表中,基于负载均衡算法选择一台 RPC Sever 发起调用。

常用注册中心:Eureka,Zookeeper(不推荐),Nacos,Consul,ETCD

配置中心

为什么使用配置中心

  • 配置实时生效 :传统的静态配置方式要想修改某个配置只能修改之后重新发布应用,要实现动态性,可以选择使用数据库,通过定时轮询访问数据库来感知配置的变化。轮询频率低感知配置变化的延时就长,轮询频率高,感知配置变化的延时就短,但比较损耗性能,需要在实时性和性能之间做折中。配置中心专门针对这个业务场景,兼顾实时性和一致性来管理动态配置
  • 配置管理流程:配置的权限管控、灰度发布、版本管理、格式检验和安全配置等一系列的配置管理相关的特性,也是配置中心不可获取的一部分;
  • 分布式场景:随着采用分布式的开发模式,项目之间的相互引用随着服务的不断增多,相互之间的调用复杂度成指数升高,每次投产或者上线新的项目时苦不堪言,需要引用配置中心治理

配置中心支持功能

  • 灰度发布:配置的灰度发布是配置中心比较重要的功能,当配置的变更影响比较大的时候,需要先在部分应用实例中验证配置的变更是否符合预期,然后再推送到所有应用实例。
  • 权限管理:配置的变更和代码变更都是对应用运行逻辑的改变,重要的配置变更常常会带来核弹的效果,对于配置变更的权限管控和审计能力同样是配置中心重要的功能。
  • 版本管理&回滚:当配置变更不符合预期的时候,需要根据配置的发布版本进行回滚。
  • 配置格式校验:应用的配置数据存储在配置中心一般都会以一种配置格式存储,比如Properties、Json、Yaml等,如果配置格式错误,会导致客户端解析配置失败引起生产故障,配置中心对配置的格式校验能够有效防止人为错误操作的发生,是配置中心核心功能中的刚需。
  • 监听查询:当排查问题或者进行统计的时候,需要知道一个配置被哪些应用实例使用到,以及一个实例使用到了哪些配置。
  • 多环境:在实际生产中,配置中心常常需要涉及多环境或者多集群,业务在开发的时候可以将开发环境和生产环境分开,或者根据不同的业务线存在多个生产环境。如果各个环境之间的相互影响比较小(开发环境影响到生产环境稳定性),配置中心可以通过逻辑隔离的方式支持多环境。
  • 多集群:当对稳定性要求比较高,不允许各个环境相互影响的时候,需要将多个环境通过多集群的方式进行物理隔离。

理论上来说,只要能作为分布式存储的服务都作为配置中心,比如说 Zookeeper 和 ETCD ,但是由于这两个工具没有方便的UI管理工具,且缺乏权限、审核、灰度发布、审核机制等,且通常定义为服务注册中心,因此不优先考虑

常用配置中心主要有:Disconf、Spring Cloud Config、Apollo 和 Nacos

快速开始

官方对应文档:Nacos 快速开始 | Nacos

安装

本次博主将会使用 Windows 系统进行演示,Linux 系统用户可以直接参考 Windows 安装流程

注:您的机器配置至少需要 2C4G 60G

因为 Nacos 依赖 Java 环境来运行。如果您是从代码开始构建并运行 Nacos,还需要为此配置 Maven环境,请确保是在以下版本环境中安装使用

  1. 64 bit OS,支持 Linux/Unix/Mac/Windows
  2. 64 bit JDK 1.8+;下载 & 配置
  3. Maven 3.2.x+;下载 & 配置

下载

我们可以通过源码和发行包 两种方式来获取 Nacos,本次将会使用源码的形式获取安装包

bash 复制代码
git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
# Windows
dir distribution/target/
# Linux
ls -al distribution/target/

# 改变 $version 为真实名称
cd distribution/target/nacos-server-$version/nacos/bin
# 博主实际命令
cd distribution/target/nacos-server-2.3.0-BETA/nacos/bin

命令执行可能出现如下问题

上面的 mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U 命令,在 CMD 命令行环境是没问题的,但是在 PowerShell 会出现 Unknown lifecycle phase ".test.skip=true". 问题

PowerShell 中应该替换为如下命令

bash 复制代码
mvn -Prelease-nacos '-Dmaven.test.skip=true' clean install -U  

配置

注:在2.2.0.1和2.2.1版本时,必须执行此变更,否则无法启动;其他版本为建议设置

修改conf目录下的application.properties文件。

设置其中的nacos.core.auth.plugin.nacos.token.secret.key值,详情可查看鉴权-自定义密钥.

注意,文档中的默认值SecretKey012345678901234567890123456789012345678901234567890123456789VGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMTIzNDU2Nzg=为公开默认值,可用于临时测试,实际使用时请务必更换为自定义的其他有效值。

启动

本次演示将会使用单机模式 / 非集群模式运行 Nacos

Windows

bash 复制代码
startup.cmd -m standalone

Linux/Unix/Mac

bash 复制代码
sh startup.sh -m standalone

如果您是 ubuntu 系统或运行脚本报错提示,请执行如下脚本

bash 复制代码
bash startup.sh -m standalone

关闭

bash 复制代码
# Windows
shutdown.cmd
# Linux/Unix/Mac
sh shutdown.sh

服务注册&发现和配置管理

服务注册

rust 复制代码
curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=nacos.naming.serviceName&ip=20.18.7.10&port=8080'

服务发现

rust 复制代码
curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=nacos.naming.serviceName'

发布配置

arduino 复制代码
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

获取配置

sql 复制代码
curl -X GET "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"

访问

启动服务之后我们可以访问地址:http://127.0.0.1:8848/nacos

用户名 / 密码:nacos/nacos

注:我这里没有鉴权,所以直接跳过登录,建议大家配置鉴权

实战

下面我们将会以分布式项目的形式,手把手带您了解 Nacos 在微服务架构中的实际应用

创建父项目

微服务中的分布式项目都会分为多个模块 ,构成父工程子工程的关系

我们需要使用 IDEA 创建父项目 nacos-demo

创建之后可以删除文件夹 src 毕竟对于父工程基本不需要,然后我们看父工程的 pom.xml(重点看注释)

初始创建的 pom.xml

xml 复制代码
<?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>

    <groupId>org.example</groupId>
    <artifactId>nacos-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

注:上面 中 SNAPSHOT 指的的快照版本 ,代表当前开发版本,区别于不同版本的就是 Maven 构建的时候都会优先查看远程是否修改,然后决定拉取,而正式版本哪怕远程已经修改,也会直接使用本地版本,而不会从远程拉取

修改之后的 pom.xml

xml 复制代码
<?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>

    <groupId>org.example</groupId>
    <artifactId>nacos-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--父工程的打包方式必须为pom-->
    <packaging>pom</packaging>

    <!--子工程-->
    <modules>
        <module>nacos-provider</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <lombok.version>1.16.18</lombok.version>
    </properties>

    <!--依赖管理-->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <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>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.2.6.RELEASE</version>
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

修改完之后重新构建 Maven 即可

这里面的 dependencyManagement 是管理版本的标签,该标签可以让子项目中引用依赖而不用显式的列出版本号 ,但是 dependencyManagement 本身只是管理依赖 ,不会导入依赖,子项目 中如果需要导入依赖,必须显式导入依赖,不会发生所谓的继承依赖

Maven 依赖搜索会沿着父子层次向上走,直到找到拥有 dependencyManagement 标签的项目,然后就会使用该 dependencyManagement 元素中指定的版本号

这样做的好处是子项目引用相同依赖,避免子项目重复声明版本 ,同时便于版本升级(因为只需要在顶层父容器中更新)

创建子模块

然后需要创建 nacos-providernacos-consumer 两个子模块,首先创建 nacos-provider

我们需要在父项目右键创建 Moduel ,如下图

注:如果您想要删除模块的话,直接删除文件,后面可能会遇到诸如"模块已经存在" "找不到模块"。您需要做的是在 .idea 文件夹下的 compiler.xml 对应 moudule 删除,或者更加简单的是,删除 .idea 文件夹,重启 IDEA

然后我们做如下修改,使得父项目指定子模块,子模块引用父项目,当然还有其他修改,这里不赘述,请直接查看源码

如果是子项目之间互相引用,比如说 nacos-provider 模块引用 nacos-consumer 模块,我们可以指定如下代码即可

xml 复制代码
<dependency>
        <groupId>org.example</groupId>
        <artifactId>nacos-consumer</artifactId>
        <version>1.0-SNAPSHOT</version>
</dependency>

nacos-consumer 模块大体类似,这里不再赘述

更多代码修改比较繁琐,大家可以直接看文章开头源码即可

Nacos 融合 Spring Boot

启动配置管理

官方对应文档:Nacos 融合 Spring Boot,成为注册配置中心 | Nacos

本章节最后会通过 Nacos Server 和 nacos-config-spring-boot-starter 实现配置的动态变更

首先我们在父项目中添加对应依赖管理,然后再分别在两个子模块中导入依赖

父项目 pom.xml

xml 复制代码
    <properties>
        <nacos.config.spring.boot.starter.version>0.2.2</nacos.config.spring.boot.starter.version>
    </properties>
xml 复制代码
            <dependency>
                <groupId>com.alibaba.boot</groupId>
                <artifactId>nacos-config-spring-boot-starter</artifactId>
                <version>${nacos.config.spring.boot.starter.version}</version>
            </dependency>

注意 :版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本

子项目的 application.yml 分别配置如下

yml 复制代码
server:
  port: 8081

spring:
  application:
    name: nacos-consumer

nacos:
  config:
    server-addr: 127.0.0.1:8848
yml 复制代码
server:
  port: 8081

spring:
  application:
    name: nacos-consumer

nacos:
  discovery:
    server-addr: 127.0.0.1:8848

我们以 nacos-provider 为例,配置如下

使用 @NacosPropertySource 加载 dataIdexample 的配置源,并开启自动更新

java 复制代码
@SpringBootApplication
@NacosPropertySource(dataId = "example", autoRefreshed = true)
public class NacosProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }

}

通过 Nacos 的 @NacosValue 注解设置属性值

java 复制代码
@Controller
@RequestMapping("config")
public class ConfigController {

    @NacosValue(value = "${useLocalCache:false}", autoRefreshed = true)
    private boolean useLocalCache;

    @GetMapping(value = "/get")
    @ResponseBody
    public boolean get() {
        return useLocalCache;
    }
}

Nacos 2.X 版本兼容 Nacos1.X 版本的OpenAPI, 请参考文档Nacos1.X OpenAPI使用

下面使用的是 v1 的 API 文档

我们启动子项目nacos-provider 之后,调用 curl http://localhost:8082/config/get,返回内容是 false

通过调用 Nacos Open API 向 Nacos server 发布配置:dataId 为example,内容为useLocalCache=true

bash 复制代码
curl -X POST "http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=example&group=DEFAULT_GROUP&content=useLocalCache=true"

再次访问 http://localhost:8082/config/get,此时返回内容为true,说明程序中的useLocalCache值已经被动态更新了。

这里说个笑话,我不小心给 clash 开了全局代理,然后我忘了,之后 Nacos 控制台就打不开了,然后用各种方法都不行,最后想起来开了全局代理

这里的命名空间容易出现问题(主要针对 v2),贴出对应官方 issue

issue:Nacos 2.2.0-配置中心 openAPI v2 无法创建与删除配置 · Issue #9783 · alibaba/nacos (github.com)

启动服务发现

该章节我们以 nacos-consumer 为例

同样是按照上面的步骤向父子项目中添加依赖(父项目添加依赖管理,子项目导入依赖)

xml 复制代码
    <properties>
        <nacos.config.spring.boot.starter.version>0.2.2</nacos.config.spring.boot.starter.version>
    </properties>
xml 复制代码
            <dependency>
                <groupId>com.alibaba.boot</groupId>
                <artifactId>nacos-discovery-spring-boot-starter</artifactId>
                <version>${nacos.config.spring.boot.starter.version}</version>
            </dependency>

然后配置对应的 application.yml(上面已经配置)

使用 @NacosInjected 注入 Nacos 的 NamingService 实例

java 复制代码
@Controller
@RequestMapping("discovery")
public class DiscoveryController {

    @NacosInjected
    private NamingService namingService;

    @GetMapping(value = "/get")
    @ResponseBody
    public List<Instance> get(@RequestParam String serviceName) throws NacosException {
        return namingService.getAllInstances(serviceName);
    }
}

启动应用之后,调用 curl http://localhost:8081/discovery/get?serviceName=example,此时返回为空 JSON 数组[]

通过调用 Nacos Open API 向 Nacos server 注册一个名称为 example 服务(成功返回 ok)

bash 复制代码
curl -X POST "http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=example&ip=127.0.0.1&port=8081"

然后再次访问 curl http://localhost:8081/discovery/get?serviceName=example,此时返回内容为

json 复制代码
[
    {
        "instanceId": "127.0.0.1#8081#DEFAULT#DEFAULT_GROUP@@example",
        "ip": "127.0.0.1",
        "port": 8081,
        "weight": 1,
        "healthy": true,
        "enabled": true,
        "ephemeral": true,
        "clusterName": "DEFAULT",
        "serviceName": "DEFAULT_GROUP@@example",
        "metadata": {},
        "ipDeleteTimeout": 30000,
        "instanceHeartBeatTimeOut": 15000,
        "instanceHeartBeatInterval": 5000
    }
]

参考链接

本文由博客一文多发平台 OpenWrite 发布!

相关推荐
ulias2121 小时前
Linux系统中的权限问题
linux·运维·服务器
码事漫谈2 小时前
当AI开始“思考”:我们是否真的准备好了?
前端·后端
青花瓷2 小时前
Ubuntu下OpenClaw的安装(豆包火山API版)
运维·服务器·ubuntu
问简3 小时前
docker 镜像相关
运维·docker·容器
Dream of maid3 小时前
Linux(下)
linux·运维·服务器
齐鲁大虾3 小时前
统信系统UOS常用命令集
linux·运维·服务器
铁东博客4 小时前
Go实现周易大衍筮法三变取爻
开发语言·后端·golang
Benszen4 小时前
Docker容器化技术实战指南
运维·docker·容器
ZzzZZzzzZZZzzzz…4 小时前
Nginx 平滑升级:从 1.26.3 到 1.28.0,用户无感知
linux·运维·nginx·平滑升级·nginx1.26.3·nginx1.28.0
oak隔壁找我4 小时前
SpringBoot中MyBatis的Mapper的原理
后端