Skip to content

Nacos简介

  • Nacos是由阿里巴巴团队使用 Java 语言开发的开源项目。

  • 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。NacosDynamic Naming and Configuration Service的首字母简称。

  • Nacos就是注册中心+配置中心的组合(Nacos = Eureka + Config + Bus)。

Nacos安装

  • 下载Nacos安装包 Nacos官网

  • 支持多种安装方式(压缩包解压即用、docker镜像运行、k8s部署)

  • bin目录下有startup.cmdstartup.sh两个启动脚本,分别适用于Windows和Linux系统。

  • 启动后默认地址是http://localhost:8848/nacos,默认用户名密码都是nacos

Nacos集群搭建

搭建一个生产可用的Nacos集群,主要包含以下几个核心步骤:

  • 环境准备:至少准备3个或以上的奇数个节点。这是由底层的一致性算法(Raft协议)所决定的,奇数个节点能有效避免选举时出现平票僵局。

  • 配置数据库:Nacos集群需要将元数据(如配置信息、用户权限)持久化到外部的共享数据库(如MySQL)。你需要创建一个数据库,并执行Nacos提供的SQL脚本来初始化表结构。

  • 修改节点配置:在每个Nacos节点的 application.properties 文件中配置上一步骤的数据库连接信息。同时,在 cluster.conf 文件中列出集群内所有节点的IP地址和端口(默认为8848)。

  • 启动与接入:逐台或同时启动所有Nacos节点。微服务应用在配置注册中心地址时,可以使用负载均衡器(如Nginx)作为统一的接入点。

集群核心工作原理

Nacos集群的设计巧妙之处在于其无中心化和数据一致性的保障。

  • 无中心化与VIP:在生产环境中,通常不会让微服务直接连接某个特定的Nacos节点。相反,会使用一个虚拟IP(VIP) 或负载均衡器(如Nginx)作为统一的接入点,从而屏蔽后端节点的物理IP,实现客户端与集群细节的解耦。

  • 数据一致性协议(Raft):Nacos集群采用 Raft一致性算法 来保证所有节点间数据的强一致性。该算法通过选举机制产生一个 Leader 节点,负责接收所有客户端的写请求(如服务注册、配置发布)。随后,Leader将数据变更同步给其他的 Follower 节点,只有大多数节点(过半)确认成功后,这次写操作才会被确认。这样可以确保即使单个节点故障,数据也不会丢失。

  • 配置同步机制:对于配置中心的数据,变更时会先写入共享数据库,然后由Leader节点通知其他节点从数据库 dump 最新数据到本地文件缓存,以提高读取性能。

  • 节点间的心跳监测:它们之间的健康感知和数据一致性是通过更底层的 Raft协议的心跳机制 来实现的。Leader节点会定期向所有Follower节点发送心跳消息(一种不包含数据内容的特殊AppendEntries RPC)这主要有两个目的:1、维持领导权:告知Follower自己仍然存活,防止触发新的选举。2、携带日志同步信息:在大多数情况下,心跳会附带日志信息,用于数据同步。如果一个Follower节点在超过选举超时时间(Election Timeout)后仍未收到Leader的心跳,它就会认为Leader已经宕机,并主动发起选举,尝试使自己成为新的Leader,以维持集群的可用性。

集群无中心化的坑

  • 由于无中心化,微服务是配置的Nginx作为统一的接入点。Nginx作为负载均衡器默认是无状态的轮询,它本身无法区分哪个Nacos节点是Leader。

  • Nacos集群节点自身内置了一套强大的“请求转发”机制。Nacos集群的每个节点都非常清楚自己在Raft组中的角色(Leader或Follower)。当客户端的一个写请求(例如,服务注册、配置发布)通过Nginx被随机分配到一个Follower节点时,Follower节点不会处理这个请求,而是会立即向客户端返回一个特定的 HTTP 状态码(如 307 Temporary Redirect) 或一个包含错误码和信息的JSON响应。这个响应的核心内容是:“我不是Leader,当前的Leader地址是 http://leader-node-ip:8848”。当客户端收到这样的重定向响应后,客户端不会向用户抛出错误,而是自动地、透明地重新发起请求,这次直接请求Follower告诉它的那个Leader地址。

注意:

由于这种特性,Follower节点给出的Leader地址是内网的,无法被访问到外网。所以会导致集群无法正常访问。

Nacos设计时已经考虑到了这种网络隔离的场景。解决方案的核心是:让每个Nacos节点明确知道“客户端通过哪个公共地址来访问我”。这样,当Follower需要返回重定向信息时,它就不会返回自己的内网地址,而是返回这个配置好的公共地址。

需要在每个Nacos节点的配置文件中conf/application.properties,添加或修改以下参数:

properties
# Nacos的IP地址(客户端能访问到的IP,即Nginx的IP或域名)
nacos.inetutils.ip-address=your.nginx.public.ip
# Nacos的端口(客户端能访问到的端口,即Nginx监听的端口,通常是80/443/8848)
nacos.inetutils.port=8848

# 另一个更直接、更推荐的配置项是(高版本Nacos):
# 指定Nacos节点对外暴露的地址,格式为 ip:port
nacos.member.list=your.nginx.public.ip:8848

Nacos的CAP模型

首先,需要理解CAP理论,它指出在一个分布式系统中,以下三者不可兼得:

  • C(Consistency)一致性:所有节点在同一时间看到的数据是完全相同的。
  • A(Availability)可用性:每个请求都能得到响应(不保证是最新数据)。
  • P(Partition Tolerance)分区容错性:系统在网络分区情况下仍然能够正常工作。

🟢 AP模式(可用性 + 分区容错性)

特点:

✅ 高可用:所有请求都能得到响应,不会因为节点间通信问题而拒绝服务

✅ 低延迟:读写操作很快,因为不需要等待所有节点同步

⚠️ 最终一致性:不保证强一致性,数据在不同节点间可能存在短暂不一致,但最终会一致

理念、场景、Nacos体现:

  • 核心理念:保证服务永远可用,即使这意味着不同节点可能暂时看到不同的数据。
  • 典型应用场景:服务注册与发现、社交媒体的点赞数、评论数、电商网站的购物车。
  • 在Nacos中的体现:当Nacos以AP模式运行时(默认的服务注册发现模式),服务实例可以向任意节点注册,节点间异步同步服务注册信息,即使部分节点宕机或网络分区,服务发现功能仍然可用。

🔵 CP模式(一致性 + 分区容错性)

特点:

✅ 强一致性:所有节点看到的数据完全相同

✅ 数据安全:不会出现数据冲突或丢失

⚠️ 可能牺牲可用性:在节点间通信失败时,为了保证一致性,系统可能拒绝写操作或部分读操作

理念、场景、Nacos体现:

  • 核心理念:保证数据绝对一致,即使这意味着在某些情况下服务不可用。
  • 典型应用场景:银行交易系统、配置信息管理、分布式锁服务。
  • 在Nacos中的体现:当Nacos以CP模式运行时(默认的配置管理模式),使用Raft协议保证配置数据的一致性,写操作必须由Leader节点处理并同步到多数节点,在网络分区时,少数派分区可能无法提供写服务。

总结

  • AP = 宁可暂时数据不一致,也要保证服务可用
  • CP = 宁可暂时服务不可用,也要保证数据一致

选择建议:

  • 对于服务注册发现,优先选择AP模式(Nacos默认)
  • 对于配置管理,优先选择CP模式(Nacos默认)

根据业务场景的容忍度来决策:能接受短暂数据不一致选AP,要求数据绝对准确选CP

在Nacos中可以通过以下方式指定模式:

bash
# 创建使用AP模式的命名空间(默认)
curl -X POST 'http://localhost:8848/nacos/v1/ns/operator/switch?entry=serverMode&value=AP'

# 创建使用CP模式的命名空间
curl -X POST 'http://localhost:8848/nacos/v1/ns/operator/switch?entry=serverMode&value=CP'

Nacos同时也支持在服务注册时指定:

java
// Spring Cloud Alibaba 示例
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
    @Bean
    public NamingService namingService() {
        // 指定命名空间,对应不同的模式
        Properties properties = new Properties();
        properties.setProperty("serverAddr", "localhost:8848");
        properties.setProperty("namespace", "您创建的命名空间ID");
        return NamingFactory.createNamingService(properties);
    }
}

如何配置Nacos

在Spring Cloud项目里配置Nacos,主要是在 bootstrap.yml 文件中进行。这是因为应用启动时需要先连接到Nacos配置中心拉取外部配置,而 bootstrap.yml 的加载优先级高于 application.yml

一个完整的 bootstrap.yml 配置文件通常如下所示:

yaml
server:
  port: 8000

spring:
  application:
    name: your-service-name # 务必设置,它是构成Data ID的一部分
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Nacos注册中心地址
      config:
        server-addr: localhost:8848 # Nacos配置中心地址
        file-extension: yaml # 指定配置格式
        namespace: your_namespace_id # 命名空间ID(添加后自动生成的一串uuid),用于环境隔离,不配置会连上默认的public空间
        group: YOUR_GROUP_NAME # 配置分组,默认为DEFAULT_GROUP
  profiles:
    active: dev # 指定当前激活的环境

Nacos通过 Data ID 来查找对应命名空间和分组下的配置,其默认生成规则是:${spring.application.name}-${spring.profiles.active}.${file-extension}

并且我们可以通过 Spring Cloud 原生注解 @RefreshScope 实现配置自动更新

实战配置Nacos

项目bootstrap.yml 配置:

yaml
server:
  port: 80

spring:
  application:
    name: OMS
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # Nacos注册中心地址
      config:
        server-addr: localhost:8848 # Nacos配置中心地址
        file-extension: yaml # 指定配置格式
        namespace: 16fd2706-8baf-433b-82eb-8c7fada847da # XX项目的命名空间ID
        group: OMS_GROUP # OMS分组,与WMS、TMS分组隔离
  profiles:
    active: prod # 指定当前激活的环境

Nacos在对应命名空间和分组下创建一个配置文件,文件名为:OMS-prod.yaml,文件内容:

yaml
your:
  config:
    item: "Nacos配置中心"

项目java代码读取配置:

java
import org.springframework.cloud.context.config.annotation.RefreshScope;

@RestController
@RefreshScope // 支持Nacos的动态刷新功能
public class MyController {

    // 从Nacos中获取配置项
    @Value("${your.config.item}")
    private String configItem;
    
    // ... 你的业务代码
}

页脚:版权前显示的信息