Spring Cloud微服务总览与注册发现详解
定位:第 01 篇,讲透微服务理念与代价、Spring Cloud 组件版图、服务注册发现机制与注册中心选型
适用版本:Spring Cloud 2023.x(Spring Boot 3.x)
说明:注册中心自身一致性原理(ZAB/RAFT/Distro)在中间件会详细展开说明,本篇只讲 Spring Cloud 视角的使用
目录
一、微服务理念
1.1 单体与微服务
| 维度 | 单体 | 微服务 |
|---|---|---|
| 部署 | 整体打包部署 | 按服务独立部署 |
| 扩缩 | 整体扩缩 | 按服务热点独立扩缩 |
| 故障 | 一损俱损 | 故障隔离在单服务 |
| 技术栈 | 统一 | 可异构(受团队能力约束) |
| 改动 | 牵连全量回归 | 小范围发布 |
1.2 微服务的代价(必须清醒认识)
① 分布式复杂性:网络不可靠、超时重试、数据一致性
② 运维成本:多服务部署、监控、日志聚合、链路追踪
③ 测试复杂度:集成链路长,契约要维护
④ 组织要求:服务边界 = 团队边界,需治理规范
不是所有系统都该微服务化------团队规模小、业务边界不清时,模块化单体是更务实的选择;微服务是手段不是目的。
1.3 服务划分原则
按业务能力/领域边界划分(DDD 限界上下文是主流方法)
高内聚低耦合:服务内聚一个能力,服务间少而稳的接口
数据独立:每服务独享数据库(避免共享库的强耦合)
二、Spring Cloud 组件版图
Spring Cloud 是微服务能力集合(非单一框架),每项能力有主流实现:
| 能力 | 主流实现 | 本篇系 |
|---|---|---|
| 注册发现 | Nacos(主流)、Eureka | 本篇 |
| 配置中心 | Nacos Config、Spring Cloud Config | CL-05 |
| 远程调用 | OpenFeign、WebClient | CL-02 |
| 负载均衡 | Spring Cloud LoadBalancer | CL-02 |
| 熔断限流降级 | Sentinel(国内主流)、Resilience4j | CL-03 |
| API 网关 | Spring Cloud Gateway | CL-04 |
| 链路追踪 | Micrometer Tracing(Brave/OTel) | CL-06 |
| 分布式事务 | Seata | CL-06 |
版本关系:Spring Cloud 用年份版本线(2023.x 对应 Boot 3.2.x),组件版本必须对齐版本线,跨线混用是常见构建失败原因。
三、服务注册发现
3.1 运行机制
① 注册:服务实例启动 → 向注册中心上报(服务名 + IP:端口 + 元数据)
② 心跳/健康检查:维持"存活"状态;失联 → 标记/剔除
③ 发现:消费方启动拉取全量 + 运行期订阅变更推送
④ 本地缓存:消费方保存实例列表,注册中心抖动不影响存量调用
⑤ 调用:从本地列表经负载均衡选实例直连(不经注册中心)
关键设计同 Dubbo(交叉引用《Dubbo》06 篇):调用不过注册中心,注册中心只管"地址目录"------所以注册中心短暂不可用不瘫痪存量流量。
3.2 Spring Cloud 侧的使用
提供方:注册中心客户端自动注册(启动注册、关闭注销)
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
spring.application.name 决定服务名
消费方:通过服务名调用
@FeignClient("order-service") 或
loadBalancerClient / WebClient + lb://order-service
3.3 健康检查与剔除
| 机制 | 说明 |
|---|---|
| 心跳上报 | 实例定时发心跳(Nacos 临时实例) |
| 服务端探测 | 注册中心主动探测实例健康 |
| 保护阈值 | 健康实例比例低于阈值时保留全部实例(防推空雪崩) |
保护阈值很重要:批量实例"失联"(如网络分区)时,与其推空地址列表,不如保留旧列表------宁可调用失败一部分,不能全量打空。
3.4 元数据的用途
实例元数据(如 version=gray)支撑路由与灰度:负载均衡/网关按元数据筛选实例,实现泳道与灰度发布(与 Dubbo 标签路由同思想)。
四、注册中心选型
| 注册中心 | 特点 | 现状 |
|---|---|---|
| Nacos | 注册 + 配置一体;AP/CP 可切换(临时实例 AP、持久实例 CP);与阿里生态亲和 | 国内主流 |
| Eureka | 经典纯注册中心,AP 模型 | 官方已停止维护(维护模式),存量为主 |
| Zookeeper | CP 倾向,强一致 | 可用但运维重,新项目少选 |
| Consul | 多数据中心支持 | 特定场景 |
选型考量:
① 一致性诉求:注册数据短暂不一致可接受 → AP;强一致 → CP
② 功能整合:注册 + 配置一体(Nacos)减少组件
③ 运维栈与生态:已有 K8s 时,Service/Endpoint 是另一种"注册中心"
④ 规模与推送性能:大规模实例数关注注册中心的推送能力
云原生视角:K8s 内服务发现可用 Service + DNS 承担,注册中心的必要性下降;Spring Cloud 与 K8s 的结合(Spring Cloud Kubernetes)是一个演进方向。
五、总结
- 微服务:独立部署/扩缩/故障隔离的收益,对应分布式复杂性、运维成本、组织要求的代价;服务按领域边界划分、数据独立。
- 组件版图:Spring Cloud 是能力集合,注册发现/配置/调用/负载/熔断/网关/链路/事务各有主流实现;版本线必须对齐。
- 注册发现:注册-心跳-发现-缓存四环节;调用不经注册中心;保护阈值防推空;元数据支撑灰度。
- 选型:Nacos 主流(注册配置一体、AP/CP 可切换);Eureka 存量;ZK 少选;K8s 环境评估 Service 原生发现。
六、常见高频面试题
1. 微服务架构的优势和代价是什么?
要点:优势------独立部署发布、按服务独立扩缩、故障隔离、技术栈灵活。代价------分布式复杂性(网络不可靠、超时重试、数据一致性难)、运维成本高(多服务监控、日志聚合、链路追踪)、集成测试复杂、需要组织与治理配套。结论:微服务是手段不是目的,团队小、边界不清时模块化单体更务实;拆分的收益要大于引入的复杂度才值得。
2. 服务如何按领域划分?有什么原则?
要点:主流方法按业务能力/领域边界(DDD 限界上下文)划分。原则:高内聚------一个服务聚焦一个能力域;低耦合------服务间接口少而稳定;数据独立------每服务独享数据库,避免共享库造成强耦合与变更牵连;边界稳定------划分依据领域概念而非技术层。演进上可从模块化单体逐步拆出高频变化或独立扩缩需求的模块。
3. 描述服务注册发现的完整流程。
要点:① 注册:实例启动向注册中心上报服务名、地址、元数据;② 存活维护:心跳上报或服务端探测,失联实例被标记剔除;③ 发现:消费方启动拉全量列表并订阅变更推送,本地缓存实例列表;④ 调用:从本地列表经负载均衡选实例直连,不经过注册中心。关键点:注册中心只管目录不在调用路径上,短暂不可用不影响存量调用;保护阈值防止异常剔除导致推空。
4. 注册中心挂了,微服务还能互相调用吗?
要点:存量调用可以------消费方本地缓存了实例列表,调用直连实例不经注册中心。受影响的是增量能力:新实例无法被发现、实例变更不再推送、新启动的服务无法注册。所以注册中心要集群高可用部署,同时消费方依赖本地缓存兜底;批量实例失联时注册中心的保护阈值避免推空地址列表造成雪崩。
5. Nacos 作为注册中心有什么特点?AP 和 CP 怎么切换?
要点:Nacos 提供注册发现 + 配置中心一体能力,减少组件数量。一致性模型按实例类型切换:临时实例(默认,服务端靠心跳维护)用 AP 模型(Distro 协议),可用性优先;持久实例用 CP 模型(Raft),强一致。微服务场景一般用临时实例(AP)------注册数据短暂不一致可接受,可用性更重要。切换靠实例注册类型配置,不是全局开关。
6. Eureka 的自我保护机制是什么?
要点:Eureka 统计心跳续约比例,当短时间内大量实例心跳丢失(如网络分区)时,进入自我保护------不再剔除这些实例,保留注册表全量。动机:宁可保留可能已失效的地址(部分调用失败),也不把地址列表清空(全量不可用)。与 Nacos 保护阈值同思想:防"注册中心误判导致推空雪崩"。注意 Eureka 已进入维护模式,新项目多选 Nacos。
7. Spring Cloud 中消费方如何用服务名调用提供方?
要点:不直接写实例地址,用服务名(提供方注册时的 spring.application.name)。方式:① OpenFeign:@FeignClient("order-service") 声明式调用;② WebClient:uri("lb://order-service/..."),lb 前缀触发负载均衡解析;③ LoadBalancerClient 编程式获取实例。底层都是:注册中心客户端解析服务名 → 本地实例列表 → 负载均衡选一个 → 替换为实际地址发起调用。
8. 实例元数据有什么用途?
要点:注册时可携带自定义元数据(key-value),消费方发现时可见。用途:① 灰度与泳道------给灰度实例打 version=gray 元数据,负载均衡/网关按元数据筛选实例定向路由;② 环境/区域标识------同注册中心内隔离不同环境流量;③ 运维信息------版本、构建号便于排障。这是"注册中心承载路由信息"的轻量实现,与 Dubbo 标签路由思想一致。
9. 微服务和 K8s Service 的服务发现是什么关系?
要点:K8s Service + DNS 本身提供服务发现能力------Pod 按标签组成 Service,通过 DNS 名访问,kube-proxy 负载均衡。全面容器化后,应用层注册中心的必要性下降(K8s 已承担注册发现与健康检查)。选择:① 用 K8s 原生发现,应用无感知;② 继续用 Nacos 等,换取配置中心、元数据路由、跨环境统一治理能力;③ Spring Cloud Kubernetes 桥接两者。趋势是基础设施能力下沉,应用层组件做减法。
10. 为什么注册中心常用 AP 模型而不是 CP?
要点:注册发现场景对可用性要求高于强一致。网络分区时:CP 模型(如 ZK 选举期)可能拒绝写入/短暂不可用,导致实例无法注册/摘除,甚至影响发现;AP 模型允许短暂数据不一致(某消费方看到的列表稍有滞后),但服务始终可用。注册数据的不一致窗口很短(秒级)且调用侧有容错(失败切换),可接受。所以 Eureka/Nacos 临时实例都选 AP。强一致需求(如某些配置数据)才用 CP 形态。
