一、想用好 Nacos,先认清它在干两件不同的事
许多开发者初识 Nacos 时,往往只把它当作“一个工具”。但深入剖析便会发现,其内部承载着两种性质迥异的职责:
- 服务注册与发现:追求速度与可用性,偶尔丢失少量数据影响不大。
- 配置管理:允许适当延迟,但数据必须绝对不丢。
这两个场景天然需要差异化的一致性策略。Nacos 的内核正是基于这一差异,构建了两套独立运作的体系:
| 模块 | 一致性 | 协议 | 典型 CAP 取舍 |
|---|---|---|---|
| 服务发现 | 最终一致 | Distro(Nacos 自研) | AP |
| 配置管理 | 强一致 | Raft(JRaft 实现) | CP |

将这张图牢记于心,后续所有逻辑便豁然开朗。
二、Distro:服务发现为啥默认用 AP
为何不采用强一致?
服务实例数量庞大且上下线频繁。若每次变更都走 Raft 那样的“多数派确认”,集群将承受巨大压力。
况且,服务发现本身的容错特性颇为特殊:
- 多一个实例,最多增加一次失败重试。
- 少一个实例,最多短暂损失部分流量处理能力。
短时间的不一致,对业务体验几乎无感。因此,此处实在没有必要强行上 CP。
Distro 的运行机制
Distro 是 Nacos 自研的协议,设计思路非常务实:
- 责任分片:每个 Nacos 节点仅负责一部分服务实例的“权威数据”。
- 本地写入、异步同步:客户端注册到任意节点后,节点先写入本地,再通过异步广播同步至其他节点。
- 最终一致性:经过短暂时间,集群内同一服务实例的视图将趋于一致。
- 节点故障可恢复:某节点宕机后,其负责的实例数据由其他节点接管,重启后还能重新拉取。

这一设计的精妙之处在于——它坦然承认“服务发现本就是 AP 场景”,并未为了追求强一致而强行套用 Raft。
三、Raft:配置中心为何必须 CP
配置管理则截然不同。
设想这样一个场景:你在控制台中将核心限流值从 1000 改为 100。如果此时 Nacos 集群内部不一致,部分节点已收到新值,部分节点仍保留旧值——
这种后果远比“多一个旧实例”严重得多。因此,配置中心必须采用 CP 模式,写入操作需在多数派确认成功后才算真正完成。
Nacos 配置中心基于 JRaft,即 Raft 协议的工程化实现版本:

有几个工程细节值得重点说明:
- 节点数必须 ≥ 3。Raft 需要选举,2 个节点无法完成。
- 写入操作均由 Leader 处理。Follower 收到写入请求后会转发或直接拒绝。
- Leader 宕机后会触发重新选举。选举期间短暂不可写入,这属于正常行为。
- 配置最终存储于 MySQL(默认)。Raft 负责协调一致性,而非存储本身。
这套机制堪称教科书级别的 CP 实现。千万不要尝试用 2 节点运行 Nacos 配置中心——从工程角度来看,这是错误的做法。
四、配置推送:长轮询,而非 WebSocket
在做技术选型时,不少人曾误以为 Nacos 配置推送走的是 WebSocket。
但事实并非如此。
它实际采用的是 长轮询(long polling)。大致流程如下:

为什么选择长轮询而非 WebSocket?
- 实现简单:基于 HTTP 协议,所有 SDK 都能轻松对接,运维和网关压力更小。
- 网络穿透性强:WebSocket 在一些企业网络中需要协议升级,而长轮询就是普通的 HTTP 请求。
- 效果近乎实时:客户端感知到变更通常在 1 秒以内,业务体验上就是“实时推送”。
很多教程会写“Nacos 是推送的”,严格来说这并不准确。它实际是通过 long-polling 模拟出的“准实时”效果。但从体验上看并无差别,工程上反而更加稳定。
五、临时实例 vs 持久实例:上一篇埋下的坑,现在拆开细讲
上一篇曾提到:“Nacos 默认是临时实例,假死会有坑”。这里展开详细说明。
两种实例的核心区别
| 类型 | 心跳保活 | 服务端剔除 | 用途 |
|---|---|---|---|
| 临时实例(默认) | 客户端心跳 | 心跳超时即剔除 | 业务微服务 |
| 持久实例 | 不依赖心跳 | 服务端主动健康检查 | 网关、固定基础设施 |
假死场景为何危险
业务微服务默认采用临时实例。问题在于:
- 进程并未完全终止,心跳线程仍在运行
- 但业务线程已卡死,无法处理请求
- 从 Nacos 视角看:心跳正常,实例状态健康
- 流量持续打入 → 大量请求超时

如何应对
常见的几种解决方案:
- 配合健康检查 / Readiness 探针。让 K8s 或网关自行判断健康状态,而非完全依赖 Nacos。
- 关键基础设施改为持久实例。比如内部网关、定时任务调度器等“挂了会影响全局”的组件,让 Nacos 主动进行健康检查。
- 下游做好熔断。再优秀的注册中心也无法保证 100% 准确,下游必须有熔断机制兜底。
这条原则应刻入团队 SOP:注册中心是辅助手段,不能替代调用方自身的容错能力。
六、客户端缓存:Nacos 挂了为何还能撑一阵
很多人并不了解:Nacos 客户端默认会将服务列表和配置缓存到本地磁盘。
这意味着什么?
- 即使 Nacos 集群整体宕机,业务短时间内仍能依靠旧的服务列表和配置继续运转。
- 服务重启时,若无法连接 Nacos,会读取本地快照完成启动。
这是 Nacos 在 AP 路径上设置的又一道保险。
但需要注意两点:
- 缓存的是上一次的快照,并非最新数据。
- 在 Nacos 完全宕机期间,新实例上下线以及配置变更均无法被感知。
线上排查时,遇到“Nacos 挂了一会儿,业务居然没受影响”的情况,原因往往就出在这个缓存机制上。
七、把这些模块拼起来,看 Nacos 的“性格”
将本文的几块内容整合起来,Nacos 的内核性格便清晰可见:

可以用一句话概括它的设计哲学:
这种性格在当今的微服务体系下非常契合。它并未试图抢占 Kafka、Etcd、ZooKeeper 各自擅长的领域,而是把“服务与配置”这两个最高频的场景做深做透。
八、看完原理,对实际接入有何启发
读懂原理之后,有几个习惯值得调整:
- 不再纠结“Nacos 是 AP 还是 CP”。它两者兼具,取决于你使用哪个模块。
- 配置中心至少部署 3 节点。这不是建议,而是底线。
- 业务侧默认要做熔断。注册中心永远无法达到 100% 可靠。
- 临时实例的假死问题,要靠 K8s 探针 + 熔断双重保险来应对。
- 配置走 long-polling 完全可行,但必须理解本地缓存的机制,否则可能被“看似推送实则缓存”的现象所迷惑。
这些并非新鲜知识,但只有真正理解了底层机制,你才会自然而然地付诸实践,而不是靠“踩一个坑才学一句”。
九、总结:内核并不复杂,但每一步都务实
Nacos 的内核并没有那种令人眼前一亮的炫酷算法。
它更像是出自一位老练工程师之手:
- 该选 AP 时就选 AP
- 该选 CP 时就选 CP
- 推送做不到真正实时,就用 long-polling 来模拟
- 客户端做缓存作为兜底
- 实例分为临时和持久,以应对不同的生命周期需求
每一步都对一线工程问题给出了清晰的回应。这正是它能支撑起国内绝大多数互联网公司微服务底座的原因所在。
下一篇将把它真正放入生产环境:多环境如何切换、集群如何搭建、踩过哪些坑、Nacos 3.0 引入的 AI Registry / MCP 管理究竟意味着什么。
