Spring Cloud 如何实现服务注册?
- 标签:Spring Cloud、微服务、后端
🏛 业务架构师
Spring Cloud 的服务注册实现以 Nacos 为例(国内标准),三步讲清:
1. 客户端自动注册(启动期):
- 引入
spring-cloud-starter-alibaba-nacos-discovery,应用启动时NacosAutoServiceRegistration执行; - 通过 Nacos 的 OpenAPI/gRPC 调用注册接口,把
服务名 + IP + 端口 + 集群 + 权重 + 元数据(版本/标签)注册上去; - 注册信息附带临时实例语义:靠心跳维持(默认 5 秒一跳),15 秒不健康、30 秒剔除——实例宕机自动摘除,扩容自动上线,弹性伸缩的注册面自动化。
2. 服务发现(消费侧):
- 消费者启动拉取服务列表并本地缓存 + 订阅变更推送(Nacos 用 UDP/gRPC 推送变更,秒级感知);
- Feign 调用时按服务名从本地列表选实例(LoadBalancer),注册中心挂了靠缓存仍可调用。
3. 健康检查双模式(Nacos 的产品差异点):
- 临时实例:客户端心跳上报(默认,微服务场景);
- 持久实例:服务端主动探测(DB、Redis 这类非 JVM"基础设施型服务"用)。
架构师视角的实践要点:
- 元数据是流量治理的载体:实例带版本/灰度标签(
version=gray),网关和 LB 按标签路由——注册中心的元数据设计直接决定灰度发布的能力; - 优雅上下线:下线前先反注册 + 网关摘流量,K8s 场景配 preStop,避免滚动发布打到正在关闭的实例;
- 注册中心高可用(Nacos 三节点集群 + 客户端缓存兜底)是上线前检查单的必选项。
🏗 系统架构师
以 Nacos 为例的注册链路:
- 自动装配:引入
spring-cloud-starter-alibaba-nacos-discovery,自动配置生效; - 注册触发:服务启动后(WebServerInitializedEvent)NacosClient 上报
服务名:IP:端口:集群:权重:元数据; - 临时实例(默认,AP 模式):客户端 5s 心跳;15s 未收到标记不健康(推送下线)、30s 未收到摘除——服务端不主动探测,靠心跳 TTL;
- 持久实例(CP 模式):Raft 强一致持久化,服务端主动健康检查——适合 db、redis 这类没有「客户端 SDK」的组件;
- 下线:正常停机 deregister 加优雅停机摘流量;宕机靠 30s 超时摘除。
架构细节:K8s 里注册的是 Pod IP(绕过 Service 的 kube-proxy,否则丢失真实来源,熔断与灰度元数据失效);消费方拿列表后本地缓存,2.x 走 gRPC 订阅推送。
治理要点:发布流程必须是「反注册 → 等待心跳/推送窗口 → 处理完存量请求 → 退出」,窗口没算对,滚动发布必有 5xx 尖刺。
💻 全栈开发专家
以 Nacos 为例(接入 10 分钟的活):
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>yaml
spring:
application:
name: order-service # 服务名 = 注册的 key
cloud:
nacos:
server-addr: nacos:8848
discovery:
namespace: prod
group: BIZ
metadata: # 元数据:灰度/版本路由用
version: v2启动自动注册:NacosServiceRegistry#register() 监听 WebServerInitializedEvent(端口确定后触发),调 Nacos API 把 IP:port + 元数据注册为临时实例;之后每 5s 心跳,15s 未达标记不健康、30s 剔除。K8s 下注册 Pod IP,多网卡时用 spring.cloud.nacos.discovery.ip 指定——注册错 IP 是经典踩坑。
消费方:@FeignClient(name = "order-service"),调用时 LoadBalancer 从本地缓存的实例列表选一个。
优雅停机配套必做:K8s preStop 里先反注册(或 server.shutdown=graceful + 睡眠),等消费方缓存刷新再杀进程——否则滚动更新期间流量打到将死实例,发布时 502 尖刺的老根因就是它。