Nacos 与 Eureka、ZooKeeper 的区别?
结论先行:三者都能做注册中心,但定位不同。Eureka 是纯 AP 的注册中心,靠客户端缓存与自我保护保证可用性;ZooKeeper 是 CP 的分布式协调器,用 ZAB 保证强一致,注册中心只是它的副业;Nacos 同时支持 AP 与 CP(临时实例走 Distro/AP,持久实例走 Raft/CP),并且注册中心 + 配置中心二合一。
1. CAP 定位
一致性 C
▲
ZK ● │ ● Nacos(持久实例,CP 模式)
│
───────────┼───────────▶ 可用性 A
│
Eureka ● ● Nacos(临时实例,AP 模式,默认)
| 组件 | 一致性协议 | CAP | 注册中心语义 |
|---|---|---|---|
| Eureka | 节点间异步复制(peer to peer) | AP | 允许短暂不一致,优先可用 |
| ZooKeeper | ZAB(Leader 写,过半确认) | CP | 选举期间不可写,注册中心不可用 |
| Nacos(临时实例) | Distro(自研 AP 协议) | AP | 心跳保活,异步同步 |
| Nacos(持久实例) | Raft(JRaft) | CP | 强一致,适合 DNS/数据库类服务 |
2. 关键能力对比
| 维度 | Eureka | ZooKeeper | Nacos |
|---|---|---|---|
| 健康检查 | 客户端心跳续约(30s) | 会话 + 临时节点 | 心跳(5s)+ 主动探测 |
| 服务发现 | 客户端拉取 + 本地缓存 | Watch 推送 | 拉取 + 推送(2.x 走 gRPC 长连接) |
| 配置中心 | 无 | 可用 znode 但难用 | 内置,支持动态刷新 |
| 权重/灰度 | 无 | 无 | 支持权重、元数据、分组 |
| 命名空间隔离 | 无 | 靠 path | namespace/group 两级 |
| 自我保护 | 有(15 分钟续约率 <85% 停止剔除) | 无 | 有健康保护阈值 |
| 控制台 | 简单 | 无(需第三方) | 完善 |
| Spring Cloud 集成 | Netflix 体系(已停更) | 需第三方 | 官方 Alibaba 体系 |
3. 为什么 ZooKeeper 不适合做注册中心
ZooKeeper 的强一致带来一个副作用:Leader 选举期间整个集群不可写。注册中心最怕这个——服务实例恰好在这段时间上下线,注册/续约全部失败,调用方可能拿到过期列表。
另外,ZK 的 Watch 是一次性的,客户端要反复注册;会话超时(默认 30s 级)与网络抖动叠加时容易误剔除实例。Eureka 的自我保护正是为这类场景设计的:宁可保留不健康实例,也不要把健康实例全剔掉。
4. 配置示例
spring:
application:
name: order-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: prod # 环境隔离
group: TRADE # 业务分组
cluster-name: SH # 同机房优先
ephemeral: true # true=临时实例(AP),false=持久实例(CP)
weight: 1.0
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
namespace: prod
group: TRADE
Eureka 的等价配置(仅作对比):
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
registry-fetch-interval-seconds: 30
instance:
lease-renewal-interval-in-seconds: 30
lease-expiration-duration-in-seconds: 90
5. 选型建议
| 场景 | 建议 |
|---|---|
| 新项目、Spring Cloud Alibaba | Nacos(注册 + 配置一体) |
| 已有 Eureka 集群、稳定运行 | 不必急着迁移,但要知道它已停更 |
| 需要强一致的元数据协调(选主、分布式锁) | ZooKeeper,而不是拿它做注册中心 |
| 多语言、K8s 环境 | Nacos 或 Consul / K8s Service |
6. 常见追问
追问一:Eureka 的自我保护是什么? 如果 15 分钟内续约失败的比例低于 85%,Eureka 认为「大面积失联更可能是网络问题而非实例宕机」,于是停止剔除任何实例。好处是避免误杀,坏处是调用方可能拿到已死的实例,必须靠客户端重试兜底。
追问二:Nacos 的 AP 和 CP 怎么切?
按实例类型切:ephemeral=true 的临时实例走 Distro(AP),ephemeral=false 的持久实例走 Raft(CP)。同一个服务内不建议混用。
追问三:Nacos 挂了,服务还能调用吗? 能,短期内可以。客户端会缓存服务列表快照到本地文件,注册中心不可用时用快照继续调用;但新实例上下线感知不到,配置也无法更新。
追问四:ZK 的临时节点不是天然适合注册吗? 临时节点确实能表达「会话存活」,但它的 CP 语义与注册中心的高可用诉求冲突,且没有权重、元数据、配置管理等注册中心必备能力,所以只能算「能用」,不算「好用」。
追问五:Consul 和它们比呢? Consul 用 Raft(CP)+ Gossip,支持多数据中心和健康检查,跨语言好;但写入受 Leader 限制,且 Spring Cloud 集成度不如 Nacos 在国内普及。
小结
三者的本质区别是一致性取舍与职责范围:Eureka 用 AP 换可用,ZK 用 CP 换强一致但把注册中心当副业,Nacos 用「按实例类型切换 AP/CP」同时覆盖两类诉求,并把配置中心纳入进来。选型时先问「注册中心能不能短时间不可用」,答案决定了 CAP 方向。