一份从零到精通的 Nacos 实战教程,专为初学者打造目录第一章:开篇 —— 为什么我们需要 Nacos?1.1 一个真实的故事1.2 微服务架构的两大基础设施1.3 为什么是 Nacos,而不是其他?1.4 你将从这份文档学到什么第二章:Nacos 是什么?2.1 一句话定义2.2 Nacos 的"前世今生"2.3 Nacos 解决的核心问题2.4 一个最简单的例子第三章:核心概念与架构3.1 命名空间(Namespace)3.2 分组(Group)3.3 配置(Configuration)3.4 服务(Service)3.5 实例(Instance)3.6 集群(Cluster)3.7 元数据(Metadata)3.8 Nacos 的整体架构3.9 AP 模式 vs CP 模式3.10 临时实例 vs 持久实例3.11 健康检查机制3.12 数据模型小结第四章:Nacos 的安装与部署4.1 准备工作4.2 三种安装方式4.3 方式一:下载二进制包4.4 方式二:从源码编译4.5 方式三:Docker 部署4.6 关于端口的特别提醒(重要!)4.7 修改默认配置4.8 切换到 MySQL 持久化4.9 关于 Nacos 控制台的初始密码4.10 验证安装是否成功第五章:服务发现详解5.1 服务发现要解决什么问题5.2 服务注册的完整流程5.3 心跳机制详解5.4 服务发现(订阅)流程5.5 健康检查的细节5.6 实战:使用 Java 原生 SDK5.7 实战:使用 Spring Cloud Alibaba5.8 服务消费方:用 RestTemplate 调用5.9 服务消费方:用 OpenFeign 调用5.10 集群与权重的妙用5.11 服务保护:推空保护5.12 常见的服务发现问题第六章:配置中心详解6.1 配置中心要解决什么问题6.2 配置中心的核心能力6.3 配置的标识6.4 第一个 Nacos 配置示例6.5 @RefreshScope 注解的原理6.6 @ConfigurationProperties 方式读取配置6.7 配置监听器6.8 多配置文件加载6.9 命名空间(Namespace)实战6.10 配置的版本管理与回滚6.11 配置的灰度发布(Beta 配置)6.12 配置的加密6.13 配置导入导出6.14 监听任意配置(不局限于本服务)6.15 配置中心的最佳实践第七章:Spring Cloud Alibaba 集成实战7.1 项目场景7.2 父工程 POM7.3 user-service 实现7.4 product-service 实现7.5 order-service 实现(核心:服务调用)7.6 gateway 网关实现7.7 启动并测试7.8 项目结构小结第八章:Nacos 高级特性8.1 权限控制详解8.2 自定义负载均衡策略8.3 实例上下线管理8.4 服务保护阈值8.5 元数据高级用法:版本路由8.6 配置历史和审计8.7 Nacos 监控集成第九章:Nacos 集群部署9.1 为什么要集群?9.2 集群架构9.3 集群部署步骤9.4 集群的常见问题9.5 容灾设计建议9.6 集群扩缩容9.7 性能调优第十章:实战项目案例10.1 项目场景:一个外卖系统10.2 命名空间规划10.3 分组规划10.4 配置规划10.5 订单服务的 bootstrap.yml10.6 业务开关的实现10.7 商家服务的同机房调用10.8 支付服务的权限隔离10.9 部署到 Kubernetes10.10 监控与告警第十一章:常见问题与最佳实践11.1 服务发现常见问题11.2 配置中心常见问题11.3 Nacos 服务端常见问题11.4 性能优化建议11.5 安全最佳实践11.6 升级建议第十二章:Nacos 与其他注册中心对比12.1 主流注册中心一览12.2 Nacos vs Eureka12.3 Nacos vs ZooKeeper12.4 Nacos vs Consul12.5 Nacos vs Apollo(配置中心专项)12.6 选型建议第十三章:Nacos 源码与原理浅析13.1 客户端发起注册的源码流程13.2 服务端接收注册的源码流程13.3 配置变更推送的源码流程13.4 Distro 协议简介13.5 JRaft 协议简介13.6 数据存储架构第十四章:总结与展望14.1 我们学到了什么14.2 Nacos 的核心价值14.3 学习 Nacos 的建议14.4 Nacos 的未来14.5 写在最后附录附录 A:Nacos 常用命令速查附录 B:常用配置项速查附录 C:Spring Cloud Alibaba 版本对应表附录 D:Nacos 客户端日志位置附录 E:Nacos 学习资源推荐第一章:开篇 —— 为什么我们需要 Nacos?1.1 一个真实的故事想象一下,你刚入职一家电商公司,公司的"老古董"系统是这样的:所有功能——用户登录、商品展示、下单付款、物流跟踪、客服系统——全部塞在一个巨大的 Java 项目里。这个项目打包出来有 500MB,启动一次需要 8 分钟。每次有人改了一行代码,整个团队都得停下来重新部署。某天,运营搞了一个秒杀活动,瞬间流量暴涨 50 倍。结果呢?整个系统崩了。不是因为下单接口扛不住,而是因为登录模块崩溃,把整台服务器拖垮了,连不参加秒杀的用户也用不了。老板拍桌子问:"为什么登录挂了,商品展示也用不了?"技术总监无奈解释:"因为它们都在同一个进程里啊……"这就是单体应用的痛——一处崩溃,全军覆没;一处发版,全员加班。于是公司决定微服务化改造。把这个庞然大物拆成几十个独立的小服务:用户服务、商品服务、订单服务、支付服务、物流服务……每个服务独立部署、独立伸缩、独立维护。但拆完之后,新的问题来了:订单服务怎么知道商品服务部署在哪台机器上?IP 是多少?端口是多少?商品服务扩容了,从 2 台变成了 20 台,订单服务怎么知道新增的 18 台机器在哪?某台支付服务挂了,网关怎么知道它挂了,不要再往那台机器发请求?数据库的连接配置写死在代码里,改一次配置就得重新打包部署 30 多个服务,运维要哭了不同环境(开发、测试、预生产、生产)的配置不一样,怎么管理才不会出错?老板说"现在所有日志级别改成 DEBUG",难道要重启 100 个服务实例?这些痛点,就是Nacos要解决的问题。1.2 微服务架构的两大基础设施在微服务的世界里,有两个东西是几乎所有项目都绕不开的:第一个,服务注册与发现(Service Discovery)简单理解:服务们的"通讯录"。每个服务启动后,主动告诉通讯录:"我叫订单服务,我在 192.168.1.10:8080,我活着。" 别的服务想找它,就去通讯录查一下:"订单服务在哪里?"第二个,配置中心(Config Center)简单理解:服务们的"配置仓库"。所有服务的配置都集中放在这里,服务启动时来取,运行中配置改了,通过仓库自动通知到每个服务。而 Nacos 就是同时提供这两种能力的一个开源产品。它的全名是:Nacos=Naming andConfigurationService翻译过来就是:命名服务 + 配置服务1.3 为什么是 Nacos,而不是其他?市面上能做服务发现的:Eureka、Consul、ZooKeeper、Nacos 能做配置中心的:Apollo、Spring Cloud Config、Nacos那为什么很多团队选择 Nacos?理由一:一个工具,搞定两件事。你不需要装 Eureka 做服务发现,再装 Apollo 做配置中心。一个 Nacos 全搞定,运维成本直接砍半。理由二:阿里巴巴出品,经过双11考验。Nacos 来源于阿里内部的 ConfigServer,在阿里内部经历了 10 多年大流量的洗礼,稳定性是经过实战检验的。理由三:Spring Cloud Alibaba 全家桶的核心。如果你用 Spring Cloud Alibaba 这套生态,那 Nacos 几乎是默认选项。理由四:中文文档完善,社区活跃。对国内开发者太友好了,出了问题去 GitHub 提 Issue,大概率能用中文交流。理由五:Eureka 已经不更新了。Spring Cloud 早期主推的 Eureka,Netflix 已经停止维护新版本。Eureka 2.x 干脆胎死腹中。理由六:支持 AP 和 CP 两种模式。这一点后面会详细讲,简单说就是:既能保证高可用,又能保证强一致,可以根据场景灵活切换。1.4 你将从这份文档学到什么这份文档不是简单的 API 罗列,而是希望让你:理解原理:不只是会用,而是知道为什么这么用会做实战:每个知识点都配有可运行的代码示例避开坑点:把常见的踩坑经验提前告诉你掌握架构:不只懂 Nacos,更懂微服务的服务治理思想读完这份文档,你应该能:独立搭建一个生产级别的 Nacos 集群在 Spring Boot/Spring Cloud 项目中熟练集成 Nacos理解 Nacos 服务发现和配置中心的核心原理知道生产环境中如何监控、调优、排障 Nacos对 Nacos 的源码核心流程有基本了解好了,故事讲完了,正餐开始。第二章:Nacos 是什么?2.1 一句话定义Nacos 是一个易于使用的、面向云原生应用的、动态服务发现与配置管理平台。这句话拆开看:易于使用:开箱即用,装上就能跑,不需要搞复杂的集群协议面向云原生:对 Kubernetes、Docker 等云原生环境天然友好动态服务发现:服务的注册、注销、上下线都是动态的、实时的配置管理:统一管理所有微服务的配置,且支持配置的动态刷新2.2 Nacos 的"前世今生"要理解 Nacos,得知道它从哪儿来。2008 年,阿里巴巴内部诞生了一个叫ConfigServer的系统,用来管理淘宝核心系统的配置。当时还没有"配置中心"这个时髦词,大家都叫它"动态推送系统"。2008 - 2018 年,这十年里 ConfigServer 经历了双11、双12、各种大促,扛住了从几千万 QPS 到几十亿 QPS 的流量增长。它和注册中心 VIPServer一起,构成了阿里中间件的核心。2018 年 7 月,阿里把 ConfigServer 和 VIPServer 的能力,加上一些云原生的新特性,合并、重构、开源,起了个新名字 ——Nacos。2019 年 1 月,Nacos 1.0.0 正式 GA(General Availability,一般可用)。这意味着它正式可以用于生产环境。2021 年 7 月,Nacos 2.0.0 发布。这是一个重大版本升级,核心变化是引入了gRPC 长连接通信,服务发现性能提升了 10 倍以上,解决了 1.x 版本中 HTTP 短连接带来的性能瓶颈。到 2024 年,Nacos 已经成为国内最主流的注册中心和配置中心之一,GitHub Star 数超过 30000,被无数公司用于生产环境。2.3 Nacos 解决的核心问题我把它归纳成"四个一":一、一个名字找到服务(服务发现)你不需要知道某个服务的 IP 和端口,只需要知道它的"名字",Nacos 会帮你找到一个可用的实例。二、一处修改全局生效(配置管理)改一个配置,所有用到这个配置的服务都能感知到,不需要重启。三、一目了然的健康状态(健康检查)Nacos 实时监控每个服务实例的健康状况,挂了的实例立马摘除,不再被调用。四、一站式管理多环境多租户(命名空间)开发、测试、生产环境彻底隔离,多个团队用一套 Nacos 不打架。2.4 一个最简单的例子让我们用一个最简单的故事来感受一下 Nacos 的作用:没有 Nacos 的时代:// 订单服务调用商品服务 public class OrderService { public ProductInfo getProduct(Long productId) { // IP 和端口写死在代码里,简直是噩梦 String url = "http://192.168.1.100:8081/product/" + productId; return restTemplate.getForObject(url, ProductInfo.class); } }问题来了:商品服务换机器了 → 改代码,重新部署商品服务扩容了 → 改代码,搞负载均衡商品服务挂了一台 → 调用方不知道,继续打过去,用户报错有了 Nacos 的时代:// 订单服务调用商品服务 public class OrderService { @Autowired private DiscoveryClient discoveryClient; public ProductInfo getProduct(Long productId) { // 通过服务名找到一个可用实例 ListServiceInstance instances = discoveryClient.getInstances("product-service"); ServiceInstance instance = instances.get(0); // 实际会用负载均衡 String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/product/" + productId; return restTemplate.getForObject(url, ProductInfo.class); } }仅仅是把 IP 端口换成"服务名"这一个改动,就让你的代码:不再依赖具体机器的 IP 端口自动适应服务的扩容缩容自动避开挂掉的实例这就是 Nacos 的"魔法"。当然,这只是冰山一角,接下来我们会一层一层揭开它的全貌。第三章:核心概念与架构学习一个新工具,最快的方法是先把它的"行话"听懂。Nacos 的世界里,有这么几个核心概念你必须搞清楚。3.1 命名空间(Namespace)类比:你公司的不同部门,每个部门各自有自己的会议室、办公区、储物柜,互不干扰。作用:主要用于环境隔离或租户隔离。典型用法:开发环境(dev)、测试环境(test)、预生产(staging)、生产环境(prod)各用一个 Namespace不同业务团队各用一个 Namespace,互不影响每个 Namespace 都有一个唯一的 ID(UUID 形式),Nacos 默认有一个public命名空间(ID 为空字符串)。视觉化:Nacos 服务器 ├── Namespace: dev (ID: a1b2c3d4-...) │ ├── 配置们... │ └── 服务们... ├── Namespace: test (ID: e5f6g7h8-...) │ ├── 配置们... │ └── 服务们... └── Namespace: prod (ID: i9j0k1l2-...) ├── 配置们... └── 服务们...不同 Namespace 之间的服务和配置完全隔离,即使名字相同也不会冲突。3.2 分组(Group)类比:同一个部门内的不同小组,比如开发部下面有"前端组"、"后端组"、"测试组"。作用:在 Namespace 内部进一步细分,通常用于区分业务模块或者用途。典型用法:按业务线分组:ORDER_GROUP、USER_GROUP、PAYMENT_GROUP按用途分组:COMMON_CONFIG(通用配置)、BUSINESS_CONFIG(业务配置)默认的 Group 名字是DEFAULT_GROUP。3.3 配置(Configuration)配置是配置中心的"操作单位"。每条配置由三个要素唯一确定:Namespace(命名空间)Group(分组)Data ID(配置 ID,通常是配置文件的"文件名")举个具体例子:NamespaceGroupData ID内容devDEFAULT_GROUPorder-service.yaml开发环境的订单服务配置prodDEFAULT_GROUPorder-service.yaml生产环境的订单服务配置devCOMMON_GROUPredis.properties开发环境的 Redis 公共配置注意:dev 和 prod 下都有order-service.yaml,但因为 Namespace 不同,所以是两条完全独立的配置,改一个不影响另一个。3.4 服务(Service)服务在 Nacos 里是一个"逻辑名字",代表一组提供相同功能的实例。举例:"订单服务"(order-service)是一个 Service这个 Service 下面可能有 5 个实例,分别部署在不同的机器上每个实例都是这个 Service 的一个"分身"服务的标识也是三层结构:Namespace(命名空间)Group(分组)Service Name(服务名)服务的默认分组也是DEFAULT_GROUP。3.5 实例(Instance)实例是一个具体运行中的服务进程,有具体的 IP 和端口。一个实例有这些重要属性:IP:实例所在机器的 IPPort:实例监听的端口Weight(权重):用于负载均衡,权重大的接更多流量Healthy(健康状态):是否健康Enabled(是否启用):管理员可以手动下线某个实例Metadata(元数据):自定义的键值对,可以放版本号、机房信息等Cluster Name(集群名):所属集群3.6 集群(Cluster)注意,这里的"集群"和我们平时说的"Nacos 集群"不是一回事!这里的 Cluster 指的是同一个服务下的实例集群。比如订单服务部署在两个机房:北京机房的实例 → 归到BJ集群上海机房的实例 → 归到SH集群这样做的好处是,可以做"同机房优先调用"——北京机房的订单服务优先调用北京机房的商品服务,减少跨机房延迟。3.7 元数据(Metadata)元数据是任意的键值对,挂在服务、集群、实例上,用来描述一些自定义信息。常见用法:版本号:version=1.2.0—— 用于灰度发布,只让特定版本的客户端调用特定版本的服务环境标签:env=gray—— 灰度环境标记业务标签:tenant=tenant-a—— 多租户标记机房:region=beijing—— 机房信息主机信息:hostname=node-013.8 Nacos 的整体架构我们从"一只眼睛看天下"的视角看 Nacos 的架构图:┌──────────────────────────────────────────┐ │ Nacos Console (UI) │ │ 给运维和开发人员的网页界面 │ └─────────────────┬────────────────────────┘ │ ┌──────────────────────────────────────┼──────────────────────────────────────┐ │ │ Nacos Server │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ OpenAPI 接入层 │ │ │ │ HTTP REST + gRPC(2.x 新增) │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ ┌──────────────────────────────────────┐ ┌─────────────────────────────┐ │ │ │ Naming Service │ │ Config Service │ │ │ │ (服务发现/服务注册) │ │ (配置中心) │ │ │ │ │ │ │ │ │ │ • 服务列表管理 │ │ • 配置的 CRUD │ │ │ │ • 实例的注册/注销 │ │ • 配置的版本管理 │ │ │ │ • 健康检查 │ │ • 配置的推送 │ │ │ │ • 路由策略 │ │ • 配置监听 │ │ │ └──────────────────────────────────────┘ └─────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ 一致性协议层 │ │ │ │ AP 模式: Distro 协议(自研) | CP 模式: Raft 协议(JRaft) │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ 数据存储层 │ │ │ │ 服务数据(内存) | 配置数据(MySQL/Derby) │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘ │ ┌────────────┴────────────┐ │ │ ┌─────────▼──────┐ ┌────────▼────────┐ │ 服务提供方 │ │ 服务消费方 │ │ (注册+心跳) │ │ (订阅+发现) │ └────────────────┘ └─────────────────┘这张图你不需要现在完全看懂,但要有个印象:Nacos 内部是分层的,有接入层、业务层、协议层、存储层。后面讲到具体细节时会一层一层展开。3.9 AP 模式 vs CP 模式这是分布式系统永恒的话题:CAP 理论。CAP 是什么?Consistency(一致性):所有节点同一时刻看到的数据是一致的Availability(可用性):任何时候,系统都能正常响应请求Partition Tolerance(分区容忍性):部分节点之间网络断了,系统还能工作CAP 理论说:这三者不可兼得,只能保两个。而对于分布式系统,P(分区容忍性)是必须的(因为网络问题不可避免),所以实际上是在 C 和 A 之间做选择。Nacos 的妙处:它两种都支持。AP 模式(默认):牺牲强一致性,保可用性节点之间数据可能短暂不一致,但每个节点都能继续提供服务使用Distro 协议(Nacos 自研)适合服务发现:大部分场景下,服务列表晚同步几秒钟没事,但绝不能因为网络问题导致整个注册中心不可用CP 模式:牺牲可用性,保强一致性数据必须达成共识才能写入使用JRaft 协议(基于 Raft 算法)适合配置中心:配置数据不能不一致,否则可能导致严重的业务问题怎么切换?通过 API 或者控制台,针对不同的服务可以设置不同的模式:临时实例(默认)→ AP 模式 持久实例 → CP 模式后面我们讲到"实例"的时候会详细讲临时实例和持久实例的区别。3.10 临时实例 vs 持久实例这两个概念是 Nacos 服务发现的核心,一定要分清楚。对比项临时实例(Ephemeral)持久实例(Persistent)是否需要心跳是,需要持续上报否,不主动上报健康检查方式客户端心跳服务端主动探测实例下线心跳超时自动删除需要手动删除适用场景微服务实例(默认)数据库、Redis 等老服务一致性协议Distro(AP)Raft(CP)默认模式✅ 是否为什么默认是临时实例?因为大部分微服务都是"用完即扔"的:容器化部署,扩缩容频繁,挂了直接重启或者起新的。让它们自己上报心跳就好,挂了 Nacos 自动摘除,运维不用操心。什么时候用持久实例?当你想把一个非微服务(比如老系统的某个 HTTP 接口、一个 MySQL 数据库)纳入 Nacos 管理时。这些服务自己不会主动上报心跳,需要 Nacos 主动去探测它们的状态。3.11 健康检查机制健康检查是 Nacos 保障服务可用性的关键。针对临时实例:客户端主动上报客户端每 5 秒发一次心跳Nacos 服务端 15 秒没收到心跳,标记为"不健康"30 秒还没收到,直接从服务列表删除针对持久实例:服务端主动探测支持三种探测方式:TCP:尝试建立 TCP 连接HTTP:发送 HTTP GET 请求,看返回 2xxMySQL:发送 SQL 查询(用于 MySQL 服务的探测)3.12 数据模型小结为了让你彻底搞明白这些层级关系,我画一个图:Nacos 数据模型: └── Namespace (命名空间,环境隔离) ├── Group (分组,业务/用途隔离) │ ├── 服务发现层 │ │ └── Service (服务,逻辑名字) │ │ └── Cluster (集群,机房/分区) │ │ └── Instance (实例,具体的 IP:Port) │ └── 配置中心层 │ └── Configuration (配置,通过 Data ID 标识)记住一个公式:服务定位:Namespace + Group + Service Name → 一组实例配置定位:Namespace + Group + Data ID → 一份配置好了,理论部分讲完了,接下来我们动手装一下 Nacos!第四章:Nacos 的安装与部署4.1 准备工作在开始安装 Nacos 之前,你需要准备:JDK 1.8 或更高版本(Nacos 2.x 推荐 JDK 8 或 JDK 11)Maven 3.2.x 或更高(如果你打算从源码编译)64 位操作系统(Linux/Unix/Mac/Windows)内存至少 2GB(生产环境建议 4GB 以上)检查 Java 环境:java -version如果看到类似openjdk version "1.8.0_xxx"的输出,说明 JDK 已经安装好了。如果没有,需要先去 Oracle 官网或者用包管理器安装 JDK。4.2 三种安装方式Nacos 提供了多种安装方式:下载二进制包直接运行(最简单,推荐新手)从源码编译(适合想看源码的开发者)Docker 容器化运行(适合云原生环境)我们逐一来看。4.3 方式一:下载二进制包步骤 1:下载安装包去 Nacos 的 GitHub Release 页面或者官方网站下载最新稳定版:https://github.com/alibaba/nacos/releases下载nacos-server-${version}.tar.gz(Linux/Mac)或nacos-server-${version}.zip(Windows)。假设我们下载的是nacos-server-2.3.0.tar.gz。步骤 2:解压安装包Linux/Mac:tar -zxvf nacos-server-2.3.0.tar.gz cd nacosWindows:右键解压,然后进入nacos目录。解压后的目录结构是这样的:nacos/ ├── bin/ # 启动脚本 │ ├── startup.sh # Linux/Mac 启动脚本 │ ├── startup.cmd # Windows 启动脚本 │ ├── shutdown.sh # Linux/Mac 停止脚本 │ └── shutdown.cmd # Windows 停止脚本 ├── conf/ # 配置文件 │ ├── application.properties # 主配置文件 │ ├── nacos-mysql.sql # MySQL 初始化脚本 │ └── cluster.conf.example # 集群配置示例 ├── data/ # 数据存储目录(默认嵌入式 Derby) ├── logs/ # 日志目录 └── target/ # 安装包内置文件步骤 3:启动 NacosLinux/Mac 单机模式启动:sh bin/startup.sh -m standaloneWindows 单机模式启动:bin\startup.cmd -m standalone注意-m standalone参数,意思是"单机模式"。如果不加,Nacos 会以集群模式启动,会去找其他节点,启动失败。启动成功后,你会看到日志输出类似这样:,--. ,--.'| ,--,: : | Nacos 2.3.0 ,`--.'`| ' : ,---. Running in stand alone mode | : : | | ' ,'\ Port: 8848 : | \ | : ,--.--. ,---. / / | Pid: 12345 | : ' '; | / \ / \. ; ,. : Console: http://localhost:8848/nacos/index.html ' ' ;. ; .--. .-. |/ / ' | |: : | | | \ | \__\/: . .. ' / ' | .; : https://nacos.io ' : | ; .' ," .--.; |' ; :__| : | | | '`--' / / ,. |' | '.'|\ \ / ' : | ; : .' \ : : `----' ; |.' | , .-./\ \ / '---' `--`---' `----'步骤 4:访问控制台打开浏览器,访问:http://localhost:8848/nacos默认用户名密码:用户名:nacos 密码:nacos成功登录后,你就能看到 Nacos 的控制台了。控制台主要分为这几个模块:配置管理:查看、新增、修改、删除配置服务管理:查看已注册的服务和实例权限控制:用户、角色、权限管理命名空间:管理命名空间集群管理:查看 Nacos 集群节点状态4.4 方式二:从源码编译适合想深入了解 Nacos 源码的同学。git clone https://github.com/alibaba/nacos.git cd nacos mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U编译完成后,在distribution/target/目录下能找到编译好的安装包。4.5 方式三:Docker 部署docker run --name nacos-standalone -e MODE=standalone \ -e PREFER_HOST_MODE=hostname \ -p 8848:8848 \ -p 9848:9848 \ -p 9849:9849 \ -d nacos/nacos-server:v2.3.0这里有几个端口需要解释:8848:主端口,用于 HTTP 通信(包括控制台访问)9848:Nacos 2.x 新增,用于客户端 gRPC 通信9849:Nacos 2.x 新增,用于服务端之间的 gRPC 通信4.6 关于端口的特别提醒(重要!)很多人从 Nacos 1.x 升级到 2.x 后,发现服务注册不上,踩了端口的坑。Nacos 2.x 启用了 gRPC 长连接,新增了两个端口:客户端 gRPC 端口 = 主端口 + 1000(默认 8848 + 1000 = 9848)服务端 gRPC 端口 = 主端口 + 1001(默认 8848 + 1001 = 9849)所以,如果你部署 Nacos 在云服务器或者用了防火墙,一定要同时开放这三个端口!4.7 修改默认配置Nacos 的配置文件在conf/application.properties,我们看看一些常用配置:# Nacos 服务端口 server.port=8848 # Nacos 控制台访问 context-path server.servlet.contextPath=/nacos # 数据存储类型(默认 derby,生产推荐 mysql) spring.datasource.platform=mysql # MySQL 配置 db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8connectTimeout=1000socketTimeout=3000autoReconnect=trueuseUnicode=trueuseSSL=falseserverTimezone=UTC db.user.0=nacos db.password.0=nacos123 # 鉴权开关(2.2.0.1 之后默认开启) nacos.core.auth.enabled=true nacos.core.auth.server.identity.key=自定义key nacos.core.auth.server.identity.value=自定义value nacos.core.auth.plugin.nacos.token.secret.key=自定义的Base64编码密钥4.8 切换到 MySQL 持久化默认情况下,Nacos 使用嵌入式数据库Derby存储配置数据。Derby 是一个 Java 实现的嵌入式数据库,虽然方便,但有两个明显缺点:数据存在本地,Nacos 集群部署时数据无法共享数据量大时性能不佳所以生产环境强烈建议切换到 MySQL。步骤 1:创建 MySQL 数据库CREATE DATABASE nacos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;步骤 2:导入初始化脚本Nacos 安装包的conf/目录下有一个nacos-mysql.sql文件,把它导入到刚创建的数据库中:mysql -uroot -p nacos conf/nacos-mysql.sql执行完后,数据库里会自动创建这些表:表名用途config_info存储所有配置config_info_aggr聚合配置config_info_beta灰度配置config_info_tag标签配置config_tags_relation配置标签关系group_capacity分组容量his_config_info历史配置permissions权限roles角色tenant_capacity租户容量tenant_info租户信息users用户步骤 3:修改application.propertiesspring.datasource.platform=mysql db.num=1 db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8connectTimeout=1000socketTimeout=3000autoReconnect=trueuseUnicode=trueuseSSL=falseserverTimezone=UTC db.user.0=root db.password.0=your_password步骤 4:重启 Nacossh bin/shutdown.sh sh bin/startup.sh -m standalone4.9 关于 Nacos 控制台的初始密码Nacos 2.2.0.1 之后,控制台不再有默认的内置密码,需要先在数据库的users表里手动添加一个用户。或者,如果你没启用鉴权(开发环境),登录默认是nacos/nacos。生产环境一定要修改默认密码,并且开启鉴权!否则你的 Nacos 就是裸奔状态,任何人都能修改配置和服务。修改密码可以在 Nacos 控制台的"权限控制 → 用户管理"里操作,也可以直接修改数据库:-- Nacos 用 BCrypt 算法加密密码 -- 这里假设新密码的 BCrypt 加密值为 $2a$10$... UPDATE users SET password = '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu' WHERE username = 'nacos'; -- 上面这个加密值对应明文 "nacos"4.10 验证安装是否成功最简单的验证方式:用 curl 命令测试一下 Nacos 的 API。测试服务注册:curl -X POST 'http://127.0.0.1:8848/nacos/v1/ns/instance?serviceName=test-serviceip=127.0.0.1port=8080'如果返回ok,说明注册成功。查询服务列表:curl -X GET 'http://127.0.0.1:8848/nacos/v1/ns/instance/list?serviceName=test-service'返回 JSON 包含我们刚注册的实例信息,说明 Nacos 工作正常。测试配置发布:curl -X POST 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test.yamlgroup=DEFAULT_GROUPcontent=hello: world'查询配置:curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test.yamlgroup=DEFAULT_GROUP'能看到hello: world,说明配置中心也工作正常了!第五章:服务发现详解服务发现是 Nacos 的两大核心功能之一,这一章我们深入剖析它。5.1 服务发现要解决什么问题回想一下我们最初的故事:微服务拆分后,服务之间互相调用,但谁也不知道对方在哪里。服务发现就是解决"找到对方"这个问题。抽象成三个动作:注册(Register):服务启动时,告诉注册中心"我来了,我在这个地址"发现(Discover):服务调用时,从注册中心获取目标服务的地址列表健康检查(Health Check):注册中心持续监控服务实例的状态,挂了就摘除把这三个动作做好,微服务之间的通讯就不会断。5.2 服务注册的完整流程让我们看一个服务实例(假设是订单服务)启动时,是怎么注册到 Nacos 的:┌──────────────┐ ┌──────────────┐ │ 订单服务实例 │ │ Nacos Server│ │ 192.168.1.10 │ │ │ │ :8080 │ │ │ └──────┬───────┘ └───────┬──────┘ │ │ │ 1. 启动时初始化 NacosNamingService │ │ │ │ 2. 发起注册请求(REGISTER_INSTANCE) │ ├───────────────────────────────────────────────│ │ { │ │ serviceName: "order-service", │ │ ip: "192.168.1.10", │ │ port: 8080, │ │ ephemeral: true, │ │ weight: 1.0, │ │ metadata: {...} │ │ } │ │ │ │ 3. Nacos 接收并验证 │ │ 4. 把实例信息加入服务列表(内存) │ │ 5. 通过 Distro 协议同步给其他 Nacos 节点 │ │ 6. 通知所有订阅这个服务的客户端 │ │ │ │───────────────────────────────────────────────┤ │ 7. 注册成功响应 │ │ │ │ 8. 启动心跳定时任务(每 5 秒一次) │ │ │ │ ─── HEARTBEAT ─────────────────────────────────│ │ ─── HEARTBEAT ─────────────────────────────────│ │ ─── HEARTBEAT ─────────────────────────────────│ │ ......(持续上报) │整个过程看起来简单,但内部细节有几点要注意:第一,注册请求是同步的还是异步的?在 Nacos 2.x 中,注册是基于gRPC 长连接的,客户端启动时会和 Nacos 服务端建立一个长连接,后续的注册、心跳、订阅都通过这个长连接进行,效率比 1.x 的 HTTP 短连接高得多。第二,如果注册失败会怎样?Nacos 客户端有内置的重试机制,会按照退避策略重试。同时,注册信息会缓存在客户端,即使 Nacos 服务端短暂不可用,客户端依然可以基于本地缓存提供服务发现能力。第三,实例如何标识唯一性?Nacos 通过Namespace + Group + ServiceName + ClusterName + IP + Port这一组信息唯一标识一个实例。注意 IP 和端口都参与标识,所以同一台机器上启动两个端口不同的实例,会被识别为两个不同的实例。5.3 心跳机制详解心跳是临时实例保持活跃的关键。Nacos 1.x 的心跳:客户端每 5 秒发一次 HTTP 请求,告诉 Nacos:"我还活着!" Nacos 服务端如果 15 秒没收到心跳,把实例标记为"不健康";30 秒还没收到,直接删除。Nacos 2.x 的心跳:由于使用了 gRPC 长连接,心跳机制变了。客户端不再主动发心跳请求,而是 Nacos 服务端通过长连接的状态来判断:长连接正常 → 实例存活长连接断开 → 实例下线这样既减少了心跳带来的网络开销,又能更快感知到实例的下线。心跳超时时间可配置:默认 5 秒间隔、15 秒不健康、30 秒删除。这些参数都可以通过元数据自定义:Instance instance = new Instance(); instance.setIp("127.0.0.1"); instance.setPort(8080); MapString, String metadata = new HashMap(); metadata.put("preserved.heart.beat.interval", "5000"); // 心跳间隔 metadata.put("preserved.heart.beat.timeout", "15000"); // 不健康超时 metadata.put("preserved.ip.delete.timeout", "30000"); // 删除超时 instance.setMetadata(metadata);注意:如果你的服务实例所在的 JVM 出现 GC 卡顿,导致心跳没及时发送,可能被误判为下线。这种情况下,可以适当调大超时时间。5.4 服务发现(订阅)流程服务消费方启动时,要从 Nacos 拿到目标服务的实例列表。这个过程也分几步:┌──────────────┐ ┌──────────────┐ │ 消费方服务 │ │ Nacos Server│ └──────┬───────┘ └───────┬──────┘ │ │ │ 1. 调用 selectInstances("order-service") │ │ │ │ 2. 检查本地缓存 │ │ └─ 有缓存:直接返回 │ │ └─ 无缓存:发起订阅请求 │ │ │ │ 3. 订阅请求(SUBSCRIBE_SERVICE) │ ├───────────────────────────────────────────────│ │ │ │───────────────────────────────────────────────┤ │ 4. 返回当前服务实例列表 │ │ │ │ 5. 把列表写入本地缓存 │ │ │ │ 6. 之后,Nacos 通过长连接推送变化 │ │───────────────────────────────────────────────┤ │ PUSH (实例增加/减少/状态变化) │ │ │ │ 7. 客户端更新本地缓存