服务注册与发现

注册中心是微服务架构的通信中枢——没有它,服务 A 不知道服务 B 在哪台机器上。一个合格的注册中心需要解决:服务怎么注册、怎么发现、怎么知道对方还活着、怎么处理故障。

一、注册中心核心能力

能力 说明
注册 服务启动时向注册中心注册自身信息(IP/端口/元数据)
心跳 定期发送心跳维持租约,注册中心据此判断服务存活
注销 服务正常下线时主动注销;异常下线时心跳超时被动剔除
订阅 消费者订阅服务列表,注册中心推送变更通知
通知 服务列表变更时通知所有订阅者(增量或全量)

CAP 视角下的注册中心:注册中心本质上是一个分布式协调系统。你在设计时必须做个选择——要一致性还是可用性:

  • CP:宁可短暂不可用,也不返回过期数据(Zookeeper)
  • AP:宁可返回过期数据,也保证服务正常响应(Eureka)
  • CP+AP 混合:不同场景不同策略(Nacos)

二、Zookeeper(CP)

Zookeeper 使用 ZAB 协议保证 CP——网络分区时牺牲可用性。Leader 宕机后重新选举需 30~120 秒,选举期间整个集群不可用。

ZK 不适合大规模微服务注册的原因

  1. 写压力大:每个服务实例定期心跳是写操作,所有写都要通过 Leader
  2. 选主期间不可用:服务无法注册/发现,新节点加入失败
  3. 无健康检查:ZK 只关心连接存活,端口还活着但业务线程全阻塞,ZK 不会剔除
  4. 存储膨胀:大量临时节点和 watcher 导致性能下降

结论:ZK 适合分布式锁、配置管理、选主等低频 + 强一致场景,不适合做高频 + 海量临时节点的注册中心。

三、Eureka(AP)

Eureka 是 Netflix 开发的服务发现组件,设计哲学是”宁可返回过期数据,也绝不拒绝服务”。

1
2
3
4
5
Eureka 集群(Peer-to-Peer):
Eureka-A ←→ Eureka-B ←→ Eureka-C
↑ ↑ ↑
Service-1 Service-2 Service-3
(注册+心跳) (注册+心跳) (注册+心跳)

自我保护模式:当 Eureka 检测到大量心跳超时(可能因为网络分区),它进入自我保护模式,不再剔除任何服务实例。理由是”可能是网络问题而非服务挂了,剔除会导致可用实例被误杀”。

1
2
正常模式:15 分钟内 85% 以上的心跳正常 → 按心跳剔除
自我保护:心跳失败比例 > 15% → 冻结剔除,保留所有实例

Eureka 的取舍

  • 优点:极端网络故障下仍可用(AP 优先)
  • 缺点:可能返回已宕机的实例(调用方需要自己容错,如重试+熔断)
  • 适用场景:对一致性要求不高的微服务环境

Eureka 2.0 已停止维护,新项目推荐 Nacos 或 Consul。

四、Nacos(CP+AP 混合)

Nacos 是阿里开源的服务发现和配置管理平台,目标是同时支持 AP(服务发现)和 CP(配置管理)。

1
2
3
4
5
6
7
┌────────────────── Nacos Server ──────────────────┐
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ 服务发现(AP) │ │ 配置管理(CP) │ │
│ │ Distro 协议 │ │ Raft 协议 │ │
│ │ 最终一致性 │ │ 强一致性 │ │
│ └─────────────────┘ └──────────────────────┘ │
└──────────────────────────────────────────────────┘

AP 模式(临时实例):基于 Distro 协议,节点间异步复制,分区时各节点独立提供服务。心跳 5s 上报一次,15s 无心跳标记不健康,30s 剔除。

CP 模式(持久实例):基于 Raft 协议,选举期间不可写但可读。适用于期望强一致的服务发现场景。

1
2
3
4
5
6
7
8
# Nacos 客户端配置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: production
ephemeral: true # true=AP临时实例, false=CP持久实例

五、Consul(CP+健康检查)

Consul 是 HashiCorp 开发的服务发现和配置中心,内置健康检查(HTTP/TCP/gRPC/脚本),原生支持多数据中心。

1
2
3
4
5
6
7
8
9
Consul 架构:
┌──────────┐ ┌──────────┐
│ Consul-A │ │ Consul-B │ ← Server (Raft 选主,3-5 个)
└────┬─────┘ └────┬─────┘
│ │
┌────┴───────────────┴────┐
│ Consul Client 集群 │ ← 每个节点运行 Agent
│ (注册 + 健康检查) │
└─────────────────────────┘

健康检查是 Consul 的亮点——支持 HTTP/TCP/GRPC/Script 多种检查方式,比单纯的心跳更可靠。

1
2
3
4
5
6
7
8
9
10
11
{
"service": {
"name": "order-service",
"port": 8080,
"check": {
"http": "http://localhost:8080/health",
"interval": "10s",
"timeout": "3s"
}
}
}

六、客户端 vs 服务端发现

维度 客户端发现 (Ribbon) 服务端发现 (K8s Service)
实现方式 客户端从注册中心拉取服务列表,本地负载均衡 请求先到负载均衡器,由其转发到后端实例
优点 无中间代理,少一跳 客户端简单,无需感知注册中心
缺点 客户端需要集成服务发现逻辑 多一跳,负载均衡器成为瓶颈
代表 Netflix Ribbon, Spring Cloud LoadBalancer K8s Service, AWS ELB

Kubernetes 中,kube-proxy + CoreDNS 提供了服务端发现模式,客户端只需要通过 Service 名称访问——IP 变化对客户端完全透明。

七、小结

选型建议:

  • 新项目首选 Nacos:功能最全、AP+CP 灵活、Spring Cloud 官方推荐
  • 多数据中心用 Consul:健康检查强、跨机房原生支持
  • Netflix 遗留项目用 Eureka:Spring Cloud 配套但已停维护
  • ZK 不要用作注册中心:设计初衷是 CP 协调服务,不适合高频注册发现