高 进阶
Nacos注册中心原理#
一句话答案#
Nacos 临时实例走 AP(Distro 协议),1.x 靠客户端 HTTP 心跳续约、2.x 起靠 gRPC 长连接判断存活;持久实例走 CP(JRaft),由服务端主动探测健康;同时支持配置管理。
核心要点
| 维度 | Nacos | Eureka | ZooKeeper |
|---|---|---|---|
| CAP 模型 | AP + CP(可切换) | AP | CP |
| 一致性协议 | Distro(AP)/ JRaft(CP) | 无,各节点平等,对等复制 | ZAB 协议(类 Paxos) |
| 健康检查 | 临时实例:1.x 客户端心跳(5s)/ 2.x gRPC 长连接存活;持久实例:服务端主动探测 | 客户端心跳(默认 30s) | Session + 临时节点 |
| 推/拉模型 | 1.x:UDP 推送 + 客户端定时拉取;2.x 起:gRPC 长连接推送 + 定时对账 | 拉(默认 30s 轮询) | 推(Watch 机制) |
| 自我保护 | 无 Eureka 式自我保护,用保护阈值替代(见下行) | 有(Renew 比例 < 85% 进入保护模式,不剔除实例) | 无(过半节点不可用则不可写) |
| 雪崩保护 | 支持(保护阈值 protectThreshold:健康实例比例低于阈值时返回全部实例,含不健康的) | 支持(自我保护模式) | 不支持(CP 模式下可能拒绝服务) |
| 配置中心 | 内置(Nacos Config) | 不支持(需搭配 Spring Cloud Config) | 可实现但需自行封装 |
| 多数据中心 | 支持(Group、Namespace) | 支持(Region/Zone) | 需要 Observer 模式 |
| 权重/灰度 | 支持(原生权重、元数据路由) | 不支持(需自行扩展) | 不支持 |
| 访问控制 | 支持(Namespace 级别隔离) | 不支持 | ACL |
| 社区维护 | 阿里巴巴活跃维护(3.x 已发布) | 当年的 Eureka 2.0 重写计划 2018 年终止;1.x 线后续以社区维护为主,仍在发版(现 2.0.x 为 Jakarta 版) | Apache 活跃但偏底层 |
选型建议:
- Nacos:首选方案。AP/CP 可切换,同时提供配置中心,功能最全面,Spring Cloud Alibaba 生态深度集成
- Eureka:仅需 AP 模型且团队有历史积累时可用;仍在维护、Spring Cloud Netflix 继续支持,但只做维护性更新,功能基本不再演进
- ZooKeeper:Dubbo 早期最常用的注册中心(现在 Dubbo 也常配 Nacos),但 CP 模型在网络分区时可能拒绝服务,不适合大规模微服务注册
面试要点:
- 注册中心应优先选择 AP 模型:网络分区时,宁可返回旧数据(某些实例可能已下线),也不要拒绝服务(CP 模型在分区时可能不可用)
- ZK 的 CP 特性对注册中心来说反而是劣势——分区时无法写入会导致服务注册失败
面试回答(2分钟版)
Nacos 是 Spring Cloud Alibaba 生态的核心组件,同时提供注册中心和配置中心能力。作为注册中心,Nacos 的最大特点是支持 AP 和 CP 两种模式切换:临时实例走 AP 模式使用 Distro 协议,优先保证可用性,1.x 客户端通过心跳维持注册,2.x 起改为 gRPC 长连接、连接断开即注销;持久实例走 CP 模式使用 JRaft 协议,优先保证一致性。健康检查方面 Nacos 同时支持客户端心跳和服务端主动探测,比 Eureka 只有客户端心跳更可靠。服务变更通知 1.x 是 UDP 推送加客户端定时拉取,2.x 起改为 gRPC 长连接推送,比 Eureka 默认 30 秒轮询实时性更好。和其他注册中心对比:Eureka 纯 AP、仍在维护但基本不再演进;ZooKeeper 纯 CP,网络分区时可能拒绝服务,对注册中心来说反而是劣势。注册中心应优先选 AP 模型,因为返回旧数据总比拒绝服务好。另外 Nacos 挂了也不影响短期服务调用,客户端有本地缓存兜底。
追问与易错
追问方向:
- “心跳检测和 Eureka 区别?”→ Nacos 支持临时实例(1.x 客户端心跳:5s 发一次、15s 未收到标记不健康、30s 删除,类似 Eureka;2.x 起靠 gRPC 长连接存活判断)和永久实例(服务端主动探测 TCP/HTTP/MySQL);Eureka 只有客户端心跳且有自我保护机制(大面积心跳丢失时不剔除),Nacos 的健康检查更灵活
- “集群怎么部署?”→ 至少 3 个节点组成集群,通过 cluster.conf 配置节点列表;临时实例一直用 Distro 协议(AP),永久实例用 Raft(CP,1.4.0 起从自研 Raft 换成 JRaft),配置数据生产环境存外置 MySQL;2.x 起客户端与服务端改用 gRPC 长连接(主端口 8848 + 偏移 1000 的 9848,集群间 9849,JRaft 7848);3.x 起最低 JDK 17、控制台独立到 8080 端口、默认开启鉴权
- “实例下线但心跳还在?”→ 可能是优雅停机没做好,应用关闭前应主动调用 deregister 注销实例;或者用 Spring Cloud 的 shutdown endpoint 配合 @PreDestroy 钩子主动下线,避免流量打到已关闭的实例
易错点:
- ❌ Nacos 挂了服务不能调——客户端有本地缓存
- ❌ Nacos 2.x 临时实例还是靠 5 秒 HTTP 心跳续约——2.x gRPC 客户端靠长连接存活判断,连接断开实例即被移除;只有 1.x 客户端或 HTTP OpenAPI 注册才走心跳
- ❌ 升级 Nacos 2.x 只开放 8848 端口就够——客户端 gRPC 走 8848+1000=9848,不放行会连不上