Spring Cloud 从零到生产级掌握
Spring Cloud 不是“会用 Feign 调接口”这么简单。它解决的是微服务拆分后的一整套协作问题:服务在哪里、请求走哪台机器、下游慢了怎么办、入口怎么统一、配置怎么统一、链路怎么追踪、老组件和新组件怎么对应。
一句话建立主线:
Spring Cloud 是微服务治理工具集。它把注册发现、远程调用、客户端负载均衡、网关路由、熔断限流、配置中心、链路追踪和消息事件组合成一套服务协作体系。
如果你想检查自己是否真的从零基础学懂到能面试、能落地、能排查,按 Spring Cloud 从零到精通验收清单 逐项验收。它把注册发现、Feign、LoadBalancer、Gateway、Sentinel、配置中心、链路追踪、商业场景和生产排查拆成可检查的问题。
学习目标
学完这一页,你要能做到:
- 解释 Spring Boot 和 Spring Cloud 的关系。
- 解释一次请求从 Gateway 到服务、从服务到服务的完整链路。
- 解释注册中心为什么需要心跳、缓存、健康检查和元数据。
- 解释 OpenFeign 为什么是接口代理,不是真正本地调用。
- 解释 Ribbon 和 Spring Cloud LoadBalancer 的关系。
- 解释 Gateway、Nginx、Ingress 的边界。
- 解释限流、熔断、降级、隔离、重试的差异和配合方式。
- 解释 Eureka、Ribbon、Hystrix、Zuul、Sleuth 和 Nacos、LoadBalancer、Sentinel、Gateway、Micrometer Tracing 的对应关系。
- 能把这些能力落到订单、支付、采集、库存、权限、接口聚合等商业场景里。
学习路线
flowchart TD
A["为什么拆微服务"] --> B["注册发现<br/>服务名到实例"]
B --> C["远程调用<br/>OpenFeign/HTTP"]
C --> D["负载均衡<br/>选择实例"]
D --> E["网关入口<br/>路由鉴权限流"]
E --> F["容错治理<br/>超时重试熔断降级"]
F --> G["配置中心<br/>环境和动态配置"]
G --> H["链路追踪<br/>traceId/span"]
H --> I["生产排查<br/>超时、雪崩、调用失败"]不要一上来背组件名。要先理解微服务拆分后产生了哪些问题,再看每个组件分别解决哪一类问题。
第一步:为什么需要 Spring Cloud
单体应用里,一个方法调用另一个方法:
orderService.createOrder(command);它们在同一个 JVM 里,方法调用失败通常就是代码异常。
微服务拆分后,订单服务调用库存服务:
order-service -> stock-service这就变成网络调用,会出现很多单体里没有的问题:
| 问题 | 具体表现 | 需要的治理能力 |
|---|---|---|
| 地址变化 | 容器重启 IP 变了 | 注册发现 |
| 多实例 | 库存服务部署 5 台 | 负载均衡 |
| 网络不稳定 | 连接超时、读取超时 | 超时、重试 |
| 下游慢 | 上游线程被占满 | 熔断、降级、隔离 |
| 外部入口多 | 每个服务都暴露公网不安全 | 网关 |
| 配置多 | 每个环境配置不同 | 配置中心 |
| 排查困难 | 一次请求跨多个服务 | 链路追踪 |
所以 Spring Cloud 不是为了“把系统拆散”,而是为了“拆散之后还能稳定协作”。
第二步:Spring Boot 和 Spring Cloud 的关系
| 对比项 | Spring Boot | Spring Cloud |
|---|---|---|
| 关注范围 | 单个服务如何快速开发、启动、运行 | 多个服务如何注册、发现、调用、治理 |
| 典型能力 | 自动配置、Starter、内嵌容器、Actuator | 注册中心、Feign、LoadBalancer、Gateway、Sentinel、配置中心 |
| 解决问题 | 少写配置,快速构建一个应用 | 服务之间稳定协作 |
| 关系 | 基础 | 建在 Spring Boot 之上 |
可以这样理解:
flowchart TD
A["Spring Framework<br/>IOC/AOP/事务"] --> B["Spring Boot<br/>自动配置和应用启动"]
B --> C["Spring Cloud<br/>微服务治理"]没有 Spring Boot,也可以做微服务;但 Spring Cloud 大量能力都是通过 Spring Boot 自动配置接入的,所以现代 Spring Cloud 项目通常建立在 Spring Boot 之上。
第三步:一次请求完整走法
典型商业系统链路:
客户端 -> Gateway -> order-service -> stock-service / user-service / pay-serviceflowchart TD
A["客户端请求"] --> B["Gateway"]
B --> C["鉴权、限流、日志、路由"]
C --> D["lb://order-service"]
D --> E["LoadBalancer 选择订单实例"]
E --> F["订单服务"]
F --> G["OpenFeign 调库存服务"]
G --> H["注册中心获取库存实例"]
H --> I["LoadBalancer 选择库存实例"]
I --> J["HTTP Client 发请求"]
J --> K["库存服务返回"]这条链路里每个组件职责不同:
| 组件 | 位置 | 职责 |
|---|---|---|
| Gateway | 外部入口 | 路由、鉴权、限流、跨域、日志 |
| 注册中心 | 基础设施 | 保存服务名和实例列表 |
| OpenFeign | 服务消费者内部 | 把接口调用变成 HTTP 请求 |
| LoadBalancer | 调用方内部 | 从实例列表中选一个 |
| Sentinel/Resilience4j | 调用前后 | 限流、熔断、降级 |
| Tracing | 全链路 | 生成和传播 traceId/span |
完整细节看 服务调用链路。
第四步:注册中心原理
注册中心不是“微服务数据库”。它保存的是服务实例的运行时信息。
服务提供者启动后注册:
serviceName = stock-service
ip = 10.0.0.21
port = 8082
status = UP
metadata = version=v1, zone=shanghai调用方按服务名发现:
stock-service -> [10.0.0.21:8082, 10.0.0.22:8082]flowchart TD
A["服务启动"] --> B["注册 IP、端口、元数据"]
B --> C["定期心跳续约"]
C --> D["注册中心维护实例状态"]
E["调用方"] --> F["按服务名获取实例列表"]
F --> G["本地缓存实例"]
G --> H["交给负载均衡选择"]为什么需要心跳:
| 如果没有 | 会怎样 |
|---|---|
| 无法知道实例是否还活着 | 调用方可能一直打到宕机实例 |
| 无法自动剔除故障实例 | 故障扩散到调用方 |
| 扩缩容后地址不同步 | 新实例没流量,旧实例仍被调用 |
注册中心挂了还能不能调用:
- 如果调用方本地有缓存,短时间内调用已有实例可能还能继续。
- 新实例注册、旧实例剔除、配置变更、健康状态更新会受影响。
- 生产上注册中心要高可用部署,客户端也要配置超时、熔断和本地缓存。
Eureka 更偏 AP,强调可用性;Nacos 同时支持注册发现和配置中心,支持命名空间、分组、元数据等能力。具体看 Eureka 和 Nacos。
第五步:OpenFeign 原理
Feign 的核心不是“远程方法调用”,而是“接口代理 + HTTP 请求生成”。
@FeignClient(name = "stock-service")
public interface StockClient {
@GetMapping("/stocks/{skuId}")
Integer getStock(@PathVariable("skuId") Long skuId);
}业务代码:
Integer stock = stockClient.getStock(1001L);底层做了这些事:
flowchart TD
A["调用接口方法"] --> B["Feign 动态代理拦截"]
B --> C["解析 @GetMapping 和参数"]
C --> D["构造 HTTP 请求"]
D --> E["按服务名找实例"]
E --> F["负载均衡选实例"]
F --> G["HTTP Client 发送"]
G --> H["Decoder 反序列化响应"]常见生产配置:
spring:
cloud:
openfeign:
client:
config:
default:
connectTimeout: 2000
readTimeout: 5000
loggerLevel: basic为什么必须设置超时:
| 超时类型 | 含义 | 不配置后果 |
|---|---|---|
| connectTimeout | 建立连接等待多久 | 目标不可达时长时间卡住 |
| readTimeout | 请求发出后等响应多久 | 下游慢时占满上游线程 |
写接口不要盲目重试。创建订单、扣库存、支付扣款如果没有幂等保护,重试可能导致重复业务动作。
第六步:负载均衡有哪些
Spring Cloud 常见负载均衡能力:
| 类型 | 技术 | 说明 |
|---|---|---|
| 客户端负载均衡 | Ribbon | Netflix 老组件,老项目常见 |
| 客户端负载均衡 | Spring Cloud LoadBalancer | 当前 Spring Cloud 官方推荐 |
| 服务端负载均衡 | Nginx、SLB、Ingress、Kubernetes Service | 调用方只访问统一入口 |
客户端负载均衡:
flowchart TD
A["order-service"] --> B["获取 stock-service 实例列表"]
B --> C["本地选择一个实例"]
C --> D["10.0.0.21:8082"]服务端负载均衡:
flowchart TD
A["调用方"] --> B["Nginx/SLB/K8s Service"]
B --> C["实例 1"]
B --> D["实例 2"]
B --> E["实例 3"]常见算法:
| 算法 | 原理 | 适合场景 |
|---|---|---|
| 轮询 | 依次选择实例 | 实例规格接近 |
| 随机 | 随机选实例 | 简单通用 |
| 权重 | 按权重分配 | 机器规格不同、灰度 |
| 同区域优先 | 优先同机房实例 | 降低跨机房延迟 |
| 元数据路由 | 按 version、tag 等选择 | 灰度发布、多版本共存 |
如果某台机器压力特别大,要看:
- 实例权重是否不一致。
- 调用方实例列表是否过期。
- 是否有长连接或连接池集中打到某台。
- 是否某些请求被路由到固定实例。
- 是否调用方数量太少导致轮询不均。
第七步:Gateway、Nginx、Ingress 边界
| 组件 | 更适合做什么 | 不适合做什么 |
|---|---|---|
| Nginx | 静态资源、反向代理、TLS、基础负载均衡 | 深度理解微服务注册中心和业务鉴权 |
| Gateway | 微服务路由、鉴权、限流、灰度、traceId | 复杂业务事务和领域规则 |
| Ingress | Kubernetes 集群入口路由 | 复杂业务逻辑 |
Gateway 处理流程:
flowchart TD
A["请求进入 Gateway"] --> B["匹配 Route"]
B --> C["Predicate 判断路径/方法/Header"]
C --> D["GlobalFilter 执行"]
D --> E["GatewayFilter 执行"]
E --> F["lb:// 服务名解析"]
F --> G["转发到后端服务"]Gateway 适合放:
- 登录态校验和基础鉴权。
- 限流。
- 黑白名单。
- traceId 生成。
- 请求日志。
- 跨域。
- 灰度路由。
不要放:
- 下单事务。
- 扣库存。
- 数据库复杂查询。
- 领域规则判断。
网关应该薄。业务规则应在对应服务里,否则网关会变成新的巨石应用。
第八步:限流、熔断、降级、重试怎么配合
这几个概念很容易混:
| 概念 | 解决什么 | 举例 |
|---|---|---|
| 超时 | 不无限等下游 | 读超时 5 秒 |
| 重试 | 偶发失败再试一次 | 查询接口超时重试 1 次 |
| 限流 | 流量太大主动拒绝 | 每秒最多 1000 请求 |
| 熔断 | 下游明显异常时快速失败 | 失败率 50% 打开熔断 |
| 降级 | 失败后返回兜底 | 推荐列表返回默认数据 |
| 隔离 | 故障范围隔开 | 独立线程池或信号量 |
正确顺序可以这样理解:
flowchart TD
A["请求进入"] --> B["限流判断"]
B --> C["熔断器是否打开"]
C --> D["发起远程调用"]
D --> E["超时控制"]
E --> F{"是否失败"}
F -->|"否"| G["返回成功"]
F -->|"是"| H["重试或记录失败"]
H --> I["触发降级或抛异常"]下游慢时只加重试会怎样:
flowchart TD
A["下游慢"] --> B["上游超时"]
B --> C["上游重试"]
C --> D["请求量被放大"]
D --> E["下游更慢"]
E --> A所以生产建议:
- 先设置合理超时。
- 查询类接口可以少量重试。
- 写类接口必须先做幂等,再考虑重试。
- 下游失败率或慢调用比例高时熔断。
- 入口或核心资源前限流。
- 兜底结果必须符合业务正确性,不能假装支付成功或库存扣减成功。
第九步:配置中心怎么用
配置中心解决多服务、多环境配置管理问题。
适合放配置中心:
| 配置 | 例子 |
|---|---|
| 业务开关 | 是否开启某医院采集 |
| 阈值 | 限流阈值、线程池大小 |
| 地址 | 第三方接口地址 |
| 灰度 | 版本开关、路由权重 |
| 非核心动态参数 | 批处理大小、超时时间 |
不建议随便动态改:
- 数据库核心连接信息。
- 影响数据一致性的规则。
- 密钥明文。
- 没有审计和回滚的关键配置。
配置动态刷新不是万能的。动态配置要有默认值、校验、审计、灰度和回滚,否则一次错误配置可能让所有服务同时故障。
第十步:链路追踪和日志
微服务排查必须有 traceId。
flowchart TD
A["Gateway 生成 traceId"] --> B["请求头透传"]
B --> C["order-service 日志打印 traceId"]
C --> D["Feign 继续透传"]
D --> E["stock-service 日志打印同一 traceId"]核心概念:
| 概念 | 含义 |
|---|---|
| traceId | 一次完整请求的唯一 ID |
| spanId | 一段调用的 ID |
| parentSpanId | 上游调用段 ID |
| MDC | 把 traceId 放进日志上下文 |
老项目常见 Sleuth,新项目常见 Micrometer Tracing、OpenTelemetry、SkyWalking。组件可以变,但目标不变:把跨服务请求串起来,定位慢在哪一段、错在哪一段。
第十一步:新旧组件对比
| 治理能力 | 经典 Netflix 体系 | 当前常用方案 | 是否必须学老组件 |
|---|---|---|---|
| 注册发现 | Eureka | Nacos、Consul、Eureka、Kubernetes | 老项目常见,建议理解 |
| 负载均衡 | Ribbon | Spring Cloud LoadBalancer | 要知道替代关系 |
| 熔断降级 | Hystrix | Sentinel、Resilience4j | 要理解熔断思想 |
| 网关 | Zuul | Spring Cloud Gateway | Zuul 老项目常见 |
| 链路追踪 | Sleuth | Micrometer Tracing、OpenTelemetry、SkyWalking | 要知道迁移方向 |
| 配置中心 | Spring Cloud Config | Nacos Config、Apollo、Config | 看公司选型 |
面试回答不要说“Ribbon 过时不用学”。正确说法是:
Ribbon 是 Netflix 老体系的客户端负载均衡组件,新项目更常用 Spring Cloud LoadBalancer。但两者解决的问题相同,都是从注册中心返回的实例列表里选择一个实例。理解 Ribbon 有助于理解老项目,理解 LoadBalancer 有助于做新项目。
商业项目场景
订单创建
Gateway -> order-service -> stock-service -> coupon-service -> pay-service关键点:
- Gateway 做鉴权、限流、traceId。
- order-service 不能长时间等库存和支付。
- 扣库存、支付必须幂等。
- 写操作不能盲目重试。
- 失败状态要落库,后续补偿。
医疗数据采集
采集调度 -> collect-service -> hospital-adapter-service -> asset-service关键点:
- 医院接口地址、采集开关、批大小放配置中心。
- 外部医院接口慢时要超时、熔断。
- 采集失败要记录批次和错误详情。
- 资产同步 ES 可用消息异步化。
- traceId 贯穿采集批次和子任务。
接口聚合
api-service -> user-service / asset-service / dictionary-service关键点:
- 聚合接口要减少循环 Feign 调用。
- 下游查询尽量批量化。
- 非核心展示字段可以降级。
- 核心权限、金额、库存不能随便降级成功。
生产排查总流程
服务调用失败
flowchart TD
A["调用失败"] --> B["服务名是否正确"]
B --> C["注册中心是否有实例"]
C --> D["实例健康状态是否 UP"]
D --> E["调用方本地缓存是否过期"]
E --> F["网络和端口是否通"]
F --> G["Feign 超时和错误日志"]
G --> H["下游应用日志和 traceId"]调用变慢
flowchart TD
A["接口变慢"] --> B["看 traceId 总耗时"]
B --> C["定位慢 span"]
C --> D["是网关慢还是服务慢"]
D --> E["是 Feign 等待还是下游处理慢"]
E --> F["查下游线程池、DB、缓存、外部接口"]雪崩风险
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 上游线程池满 | 下游慢,Feign 等待 | 超时、熔断、降级 |
| 下游 QPS 暴涨 | 重试放大流量 | 降低重试、退避、限流 |
| 某服务全部超时 | 数据库慢或线程池耗尽 | 查慢 SQL、线程栈、连接池 |
| Gateway 502/504 | 后端不可用或超时 | 查路由、实例、超时、下游日志 |
最小 Demo
Feign Client
@FeignClient(name = "asset-service", fallback = AssetClientFallback.class)
public interface AssetClient {
@GetMapping("/assets/{id}")
AssetDTO getAsset(@PathVariable("id") Long id);
}Fallback
@Component
public class AssetClientFallback implements AssetClient {
@Override
public AssetDTO getAsset(Long id) {
return new AssetDTO(id, "unknown", "DOWNSTREAM_UNAVAILABLE");
}
}调用方
@RestController
@RequestMapping("/reports")
public class ReportController {
private final AssetClient assetClient;
public ReportController(AssetClient assetClient) {
this.assetClient = assetClient;
}
@GetMapping("/{assetId}")
public ReportVO report(@PathVariable Long assetId) {
AssetDTO asset = assetClient.getAsset(assetId);
return new ReportVO(assetId, asset.name(), asset.status());
}
}配置
spring:
application:
name: report-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
openfeign:
client:
config:
default:
connectTimeout: 2000
readTimeout: 5000这个 Demo 的重点不是“代码能写多复杂”,而是要看懂:接口代理、服务发现、负载均衡、HTTP 调用、超时和降级是怎么组合起来的。
面试标准回答
Spring Cloud 是什么
Spring Cloud 是微服务治理工具集,建立在 Spring Boot 之上,解决多个服务之间的注册发现、远程调用、负载均衡、网关路由、熔断限流、配置中心、链路追踪等协作问题。它不是单个组件,而是一套围绕服务稳定调用的治理体系。
服务调用链路怎么回答
服务提供者启动后把服务名、IP、端口和元数据注册到注册中心。调用方通过 OpenFeign 调接口时,Feign 代理会把接口方法解析成 HTTP 请求,再按服务名从注册中心拿实例列表,由 Spring Cloud LoadBalancer 选择一个实例,最后通过 HTTP Client 发请求。生产环境还要配合超时、重试、熔断、限流、降级和链路追踪,避免下游故障拖垮上游。
负载均衡有哪些
Spring Cloud 里常见客户端负载均衡,老项目是 Ribbon,新项目是 Spring Cloud LoadBalancer;入口层也常见 Nginx、SLB、Ingress、Kubernetes Service 这类服务端负载均衡。客户端负载均衡由调用方获取实例列表并本地选择实例,服务端负载均衡由统一代理层选择后端实例。
限流、熔断、降级区别
限流是流量太大时主动拒绝部分请求;熔断是下游失败率或慢调用比例过高时快速失败,防止继续打爆下游;降级是失败或熔断后返回可接受的兜底结果。它们通常和超时、重试、隔离一起使用。
关联知识点
- Spring Cloud 总览
- Spring Cloud 从零到精通验收清单
- Spring Cloud 商业场景训练营
- 技术演进与选型
- 服务调用链路
- Eureka 注册中心
- Nacos 注册配置
- OpenFeign 远程调用
- Ribbon 与 LoadBalancer
- Gateway 网关
- Sentinel 限流熔断
- Resilience4j现代稳定性治理
- Hystrix经典组件与迁移
- 配置中心
- 链路追踪与可观测性
- Spring Cloud 面试知识点
本章小结
Spring Cloud 要按治理问题学习,而不是按组件名背诵。注册中心解决服务地址变化,OpenFeign 解决声明式 HTTP 调用,LoadBalancer 解决实例选择,Gateway 解决统一入口,Sentinel/Resilience4j 解决故障保护,配置中心解决配置管理,链路追踪解决跨服务排查。把这些能力串成一条请求链路,才算真正理解 Spring Cloud。
