Skip to content

Spring Cloud 从零到精通验收清单

这页用来验收你是否真正学懂 Spring Cloud。不是会背 Eureka、Feign、Gateway、Sentinel 这些名字就算会,而是要能说清:微服务为什么需要治理,一个服务名怎样变成真实 IP,一次 HTTP 调用经过哪些组件,负载均衡、超时、重试、熔断、限流分别解决什么问题,配置中心和链路追踪怎样支撑生产排查。

Spring Cloud 的主线是一句话:

服务先注册,调用方按服务名发现实例,负载均衡选择实例,HTTP 客户端发起远程调用,网关统一入口,熔断限流保护链路,配置中心统一参数,链路追踪帮助排查。

最终目标

能力达标标准
零基础能懂能解释 Spring Boot 和 Spring Cloud 的关系,知道为什么单体变微服务后需要治理
原理能讲能画出注册发现、Feign 调用、LoadBalancer、Gateway、Sentinel、配置中心、链路追踪全过程
Demo 能写能写最小注册中心、Feign 调用、Gateway 路由、Sentinel 限流、Nacos 配置 Demo
项目能落地能放到订单、库存、支付、资产、医疗采集等商业链路里说明
故障能排查能排查无实例、404、503、超时、重试风暴、限流误杀、配置不生效
面试能闭环面试页放标准回答,原理回到知识点页展开

总路线

mermaid
flowchart TD
    A["为什么需要微服务治理"] --> B["Spring Boot 和 Spring Cloud 关系"]
    B --> C["注册中心和服务发现"]
    C --> D["OpenFeign 远程调用"]
    D --> E["LoadBalancer 选择实例"]
    E --> F["Gateway 统一入口"]
    F --> G["超时、重试、熔断、限流、降级"]
    G --> H["配置中心和动态刷新"]
    H --> I["链路追踪和可观测性"]
    I --> J["商业场景和生产排查"]

阶段 1:为什么需要 Spring Cloud

单体到微服务后发生了什么

单体应用里,模块之间通常是本地方法调用:

java
orderService.createOrder(command);

拆成微服务后,订单服务、库存服务、支付服务、用户服务变成多个进程,甚至部署在不同机器、不同容器、不同机房。一次“创建订单”可能变成:

mermaid
flowchart TD
    A["订单服务"] --> B["库存服务"]
    A --> C["用户服务"]
    A --> D["优惠券服务"]
    A --> E["支付服务"]

这时会出现单体里没有的问题:

问题如果不治理会怎样
服务地址会变调用方写死 IP,扩容、迁移、重启都要改配置
实例数量变多不知道请求该打到哪台机器
下游会慢或挂上游线程被拖住,故障扩散成雪崩
外部入口变多鉴权、限流、日志、跨域到处重复
配置到处分散环境混乱、改配置要发版、无法审计回滚
调用链变长线上慢请求不知道卡在哪个服务

Spring Cloud 解决的不是“如何写业务代码”,而是“服务拆开以后如何稳定协作”。

详细知识点:Spring Cloud 从零到生产级掌握

阶段 2:Spring Boot 和 Spring Cloud 的关系

Spring Boot 解决单个应用怎么快速启动、自动配置、暴露接口、接入数据库和监控。Spring Cloud 解决多个 Spring Boot 应用之间如何协作。

对比项Spring BootSpring Cloud
关注对象单个服务多个服务组成的系统
解决问题启动、配置、Web、监控、部署注册发现、远程调用、负载、网关、熔断、配置中心、追踪
常见能力Starter、自动配置、内嵌 Tomcat、ActuatorNacos/Eureka、Feign、LoadBalancer、Gateway、Sentinel
学习顺序先学后学

Spring Cloud 的很多能力本质上也是通过 Spring Boot 自动配置接入的。例如引入 OpenFeign Starter 后,启动时扫描 @FeignClient 接口,注册代理 Bean,业务代码才能像注入普通 Bean 一样注入 Feign Client。

阶段 3:服务注册和服务发现

注册中心做什么

注册中心维护的是“服务名 -> 实例列表”的映射。

mermaid
flowchart TD
    A["order-service 实例1"] --> C["注册中心"]
    B["order-service 实例2"] --> C
    D["stock-service 实例1"] --> C
    E["调用方"] --> C
    C --> F["返回服务实例列表"]

服务提供者启动后会注册:

  • 服务名。
  • IP 和端口。
  • 健康状态。
  • 集群、版本、权重、机房等元数据。

调用方不会每次都实时查注册中心,通常会拉取或订阅实例列表,缓存在本地。这样可以降低注册中心压力,也能在注册中心短暂不可用时继续调用已有实例。

Eureka 和 Nacos

对比项EurekaNacos
生态Spring Cloud Netflix 老体系Spring Cloud Alibaba 常用
定位注册中心注册中心 + 配置中心
一致性倾向偏 AP,强调可用性和客户端缓存支持临时实例、永久实例、命名空间、配置管理
老项目常见部分项目迁移目标
新项目仍可维护Alibaba 生态常用

服务发现不到怎么排查

现象排查方向
注册中心没有实例服务没启动、注册配置错、网络不通
控制台有实例但调用方没有namespace、group、region、缓存刷新、服务名不一致
有实例但不可用健康状态 DOWN、权重 0、灰度过滤、IP 不可达
下线后仍被调用注册剔除和客户端缓存刷新存在传播窗口

详细知识点:EurekaNacos

阶段 4:OpenFeign 远程调用

Feign 是什么

Feign 是声明式 HTTP 客户端。它让你写一个接口,运行时生成代理对象,把接口调用转换成 HTTP 请求。

java
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "stock-service")
public interface StockClient {
    @GetMapping("/stock/{skuId}")
    Integer getStock(@PathVariable("skuId") Long skuId);
}

业务代码:

java
import org.springframework.stereotype.Service;

@Service
public class OrderService {
    private final StockClient stockClient;

    public OrderService(StockClient stockClient) {
        this.stockClient = stockClient;
    }

    public void createOrder(Long skuId) {
        Integer stock = stockClient.getStock(skuId);
        if (stock <= 0) {
            throw new IllegalStateException("stock not enough");
        }
    }
}

Feign 调用全过程

mermaid
flowchart TD
    A["调用 Feign 接口方法"] --> B["JDK 动态代理拦截"]
    B --> C["解析方法注解"]
    C --> D["组装 RequestTemplate"]
    D --> E["Encoder 序列化请求"]
    E --> F["RequestInterceptor 添加请求头"]
    F --> G["LoadBalancer 选择实例"]
    G --> H["HTTP Client 发送请求"]
    H --> I["Decoder 反序列化响应"]

Feign 不是本地调用

Feign 写法像本地方法,但本质仍是远程 HTTP:

  • 可能连接超时。
  • 可能读取超时。
  • 可能下游返回 500。
  • 可能服务无实例。
  • 可能序列化失败。
  • 写操作重试可能导致重复扣库存或重复支付。

生产必须配置超时、错误处理、日志、traceId、熔断降级和幂等。

详细知识点:OpenFeign

阶段 5:LoadBalancer 负载均衡

负载均衡解决什么

一个服务通常有多个实例,调用方要从实例列表里选一个。

mermaid
flowchart TD
    A["调用 stock-service"] --> B["获取实例列表"]
    B --> C["实例1 10.0.0.1:8080"]
    B --> D["实例2 10.0.0.2:8080"]
    B --> E["实例3 10.0.0.3:8080"]
    C --> F["LoadBalancer 选择一个"]
    D --> F
    E --> F

Ribbon 和 Spring Cloud LoadBalancer

对比项RibbonSpring Cloud LoadBalancer
时代Netflix 老体系当前 Spring Cloud 官方方案
核心职责客户端选择实例客户端选择实例
扩展点IRuleIPingServerListServiceInstanceListSupplierReactorServiceInstanceLoadBalancer
当前建议老项目维护要懂新项目优先理解

负载不均为什么发生

负载均衡不是保证每台机器请求数绝对相同。负载不均可能来自:

  • 实例配置不同。
  • 某些请求耗时特别长。
  • HTTP 连接池复用旧连接。
  • 灰度或权重规则偏流。
  • 热租户集中访问某类接口。
  • 某台实例 Full GC 或慢 SQL,但注册中心仍认为健康。

排查不能只看请求数,要看每个实例的 QPS、P95/P99、错误率、CPU、线程池、连接池、GC、慢 SQL。

详细知识点:Spring Cloud 负载均衡

阶段 6:Gateway 统一入口

Gateway 做什么

Gateway 是微服务统一入口,适合做:

  • 路由转发。
  • 登录态校验。
  • 限流。
  • 跨域。
  • 灰度。
  • 统一日志。
  • traceId 透传。
  • 请求和响应头处理。

不适合做复杂业务、数据库事务和领域规则。

Route、Predicate、Filter

概念作用
Route一条路由规则,决定转发到哪里
Predicate判断请求是否命中路由
Filter命中后在转发前后做处理
yaml
spring:
  cloud:
    gateway:
      routes:
        - id: asset-service
          uri: lb://asset-service
          predicates:
            - Path=/assets/**
          filters:
            - StripPrefix=1

lb:// 怎么变成真实地址

mermaid
flowchart TD
    A["请求 /assets/list"] --> B["Gateway 匹配 Route"]
    B --> C["识别 uri=lb://asset-service"]
    C --> D["从注册中心或缓存拿实例"]
    D --> E["LoadBalancer 选择实例"]
    E --> F["替换为 http://IP:Port"]
    F --> G["Netty HTTP 转发"]

详细知识点:Spring Cloud Gateway

阶段 7:超时、重试、熔断、限流、降级

这几个概念经常被混在一起,必须分清边界。

能力解决什么不解决什么
超时下游迟迟不返回时释放上游线程不能证明下游没有执行成功
重试偶发失败恢复下游整体慢时会放大流量
熔断下游持续异常时快速失败不能恢复下游服务
限流入口流量太大时保护系统不是权限控制
降级失败时返回兜底结果不能把关键写操作伪装成功

重试风暴

假设入口 1000 QPS,Feign 最多重试 2 次。下游慢时,理论上可能变成 3000 QPS 打到下游:

mermaid
flowchart TD
    A["原始请求 1000 QPS"] --> B["第一次调用"]
    B --> C["超时"]
    C --> D["重试 1 次"]
    D --> E["再次超时"]
    E --> F["重试 2 次"]
    F --> G["下游压力被放大"]

写操作重试必须有幂等键、状态查询或补偿机制。支付、扣库存、创建订单不能盲目重试。

Sentinel 原理

Sentinel 把接口、方法、下游调用抽象成资源。请求进入资源时经过 SlotChain,统计 QPS、线程数、慢调用比例、异常比例,再根据规则判断是否放行。

mermaid
flowchart TD
    A["请求进入资源"] --> B["构建调用上下文"]
    B --> C["统计 QPS、RT、异常"]
    C --> D["流控规则判断"]
    D --> E["熔断规则判断"]
    E --> F["系统保护判断"]
    F --> G{"是否通过"}
    G -->|是| H["执行业务"]
    G -->|否| I["BlockException"]

详细知识点:SentinelResilience4j现代稳定性治理Hystrix经典组件与迁移

阶段 8:配置中心

配置中心解决什么

配置中心不是“把 yml 放到网页上”,而是解决多服务、多环境、多实例的配置治理:

  • 环境隔离。
  • 权限控制。
  • 审计记录。
  • 灰度发布。
  • 动态刷新。
  • 回滚。
  • 本地快照。
  • 敏感配置治理。

加载流程

mermaid
flowchart TD
    A["应用启动早期"] --> B["读取本地引导配置"]
    B --> C["连接配置中心"]
    C --> D["按 Namespace、Group、DataId 定位配置"]
    D --> E["拉取远程配置"]
    E --> F["加入 Spring Environment"]
    F --> G["自动配置和 Bean 读取最终配置"]

配置中心必须尽量早加载,因为数据源、Redis、Feign 超时、线程池、Sentinel 规则等很多 Bean 创建时就要读取配置。如果加载太晚,Bean 已经按默认值创建,后续刷新不一定安全。

动态刷新不是万能

适合动态刷新的配置:

  • 功能开关。
  • 限流阈值。
  • 灰度比例。
  • 文案或低风险参数。

不适合随便刷新的配置:

  • 数据源连接。
  • MQ 消费组。
  • 复杂线程池。
  • 证书密钥。
  • 影响事务和长连接状态的配置。

详细知识点:Spring Cloud 配置中心

阶段 9:链路追踪和可观测性

链路追踪解决什么

一次请求可能经过 Gateway、订单服务、库存服务、支付服务、消息服务。没有 traceId 时,线上慢请求像在雾里找针。

mermaid
flowchart TD
    A["Gateway span"] --> B["order-service span"]
    B --> C["stock-service span"]
    B --> D["pay-service span"]
    B --> E["MQ send span"]

核心概念:

概念说明
traceId一次完整请求的全局 ID
spanId一段调用的 ID
parentSpanId父调用 ID
baggage跨服务传播的上下文
日志关联日志里打印 traceId,方便从链路跳日志

老项目常见 Sleuth,新项目常见 Micrometer Tracing、OpenTelemetry、SkyWalking。

详细知识点:链路追踪与可观测性

阶段 10:Spring Cloud Stream 和 Bus

微服务之间不只有同步 HTTP 调用,也需要异步事件。

技术作用场景
Spring Cloud Stream抽象 Kafka/RabbitMQ 等消息中间件订单事件、采集完成事件
Spring Cloud Bus广播 Spring Cloud 系统事件配置刷新广播

异步事件要关注最终一致、幂等、重试、死信、积压、顺序和链路追踪。不能因为用了 Stream 就忽略 MQ 的基础问题。

详细知识点:Stream 与 Bus

阶段 11:商业场景验收

场景 1:资产详情查询

链路:

mermaid
flowchart TD
    A["前端"] --> B["Gateway"]
    B --> C["asset-service"]
    C --> D["dict-service"]
    C --> E["permission-service"]
    C --> F["Redis 或 MySQL"]

验收问题:

  • Gateway 做哪些事?哪些事不能放 Gateway?
  • asset-service 调 dict-service 时,服务名如何变成真实 IP?
  • dict-service 慢时,asset-service 怎么超时、熔断、降级?
  • 如何用 traceId 定位慢在字典、权限还是数据库?

场景 2:医疗采集任务

链路:

  • 采集服务从配置中心读取医院接口地址、开关、线程池参数。
  • 采集服务调用字典服务和资产服务。
  • 医院接口慢时不能无限重试。
  • 失败批次记录原因,后续补偿。
  • 关键接口按医院编码或租户限流。

验收问题:

  • 配置中心改线程池参数为什么不能随便动态刷新?
  • 医院接口超时后能不能立刻重试?如何避免放大故障?
  • Sentinel 热点参数限流为什么适合按 hospitalCode

场景 3:服务上线和优雅下线

流程:

mermaid
flowchart TD
    A["新实例启动"] --> B["通过健康检查"]
    B --> C["注册到注册中心"]
    C --> D["调用方刷新实例缓存"]
    D --> E["开始接流量"]
    E --> F["下线前置 Readiness 不可用"]
    F --> G["注册中心摘除"]
    G --> H["等待缓存刷新和请求处理完成"]
    H --> I["关闭进程"]

验收问题:

  • 为什么服务下线后短时间还可能被调用?
  • K8s readiness、preStop、graceful shutdown 各自解决什么?
  • HTTP 连接池为什么会继续影响调用?

阶段 12:生产排查

服务调用失败决策树

mermaid
flowchart TD
    A["服务调用失败"] --> B{"是否经过 Gateway"}
    B -->|是| C["看 Gateway 状态码"]
    C --> D["404 查路由 Predicate"]
    C --> E["503 查注册中心和实例"]
    C --> F["504 查下游超时"]
    B -->|否| G["看 Feign 错误"]
    G --> H["无实例查服务名和 namespace"]
    G --> I["连接超时查网络和端口"]
    G --> J["读取超时查下游耗时"]

高频故障

故障排查重点
Feign 无实例服务名、Namespace、Group、实例健康、本地缓存
Gateway 404Route 是否命中、Path/Method/Header、StripPrefix
Gateway 503lb:// 服务名、实例列表、健康状态、灰度过滤
Read timeout下游线程池、慢 SQL、锁、GC、第三方接口
连接池耗尽HTTP Client 连接池、每路由连接数、连接泄漏
负载不均实例指标、权重、灰度、长连接、慢实例
Sentinel 拦截Flow/Degrade/Param/System/Authority 具体异常类型
配置不生效Namespace、Group、DataId、profile、优先级、Bean 是否刷新
traceId 丢失线程池、异步、MQ、网关过滤器顺序、日志格式

阶段 13:面试闭环

mermaid
flowchart TD
    A["面试题"] --> B["标准回答"]
    B --> C["回知识点页看原理"]
    C --> D["画调用链路"]
    D --> E["说商业场景"]
    E --> F["补故障排查"]
面试题必须答到的深度
Spring Cloud 是什么微服务治理工具集,不是单个框架
一次调用怎么走Gateway、Feign、注册中心、LoadBalancer、HTTP Client、Sentinel、Tracing
注册中心做什么服务注册、续约、发现、本地缓存、健康状态、元数据
Feign 原理动态代理、注解解析、编码解码、拦截器、HTTP Client
负载均衡服务实例列表、过滤、选择算法、Ribbon/LoadBalancer 差异
GatewayRoute、Predicate、Filter、lb://、Netty 转发
熔断限流超时、重试、熔断、限流、降级边界
配置中心启动早期加载、Environment、动态刷新边界
链路追踪traceId、span、上下文传播、日志关联
生产排查无实例、404、503、超时、配置不生效、traceId 丢失

面试标准回答看:Spring Cloud 面试知识点

最终验收题

  1. Spring Boot 和 Spring Cloud 的区别是什么?
  2. 为什么微服务不能写死 IP?
  3. 注册中心保存哪些信息?
  4. 调用方为什么要缓存实例列表?
  5. Eureka 为什么偏 AP?
  6. Nacos 的 Namespace、Group、DataId 分别解决什么?
  7. Feign 为什么不是本地调用?
  8. Feign 接口方法如何变成 HTTP 请求?
  9. Encoder、Decoder、RequestInterceptor 各自做什么?
  10. Ribbon 和 Spring Cloud LoadBalancer 区别是什么?
  11. 客户端负载均衡和服务端负载均衡区别是什么?
  12. lb://service-name 如何变成真实 IP?
  13. Gateway 的 Route、Predicate、Filter 怎么协作?
  14. 为什么网关不能写复杂业务?
  15. 超时、重试、熔断、限流、降级分别解决什么?
  16. 为什么写操作不能盲目重试?
  17. Sentinel 的资源、规则、滑动窗口、SlotChain 怎么理解?
  18. 配置中心为什么要启动早期加载?
  19. 动态刷新为什么不是万能的?
  20. 配置不生效怎么排查?
  21. traceId 和 spanId 区别是什么?
  22. 异步线程或 MQ 为什么可能丢 traceId?
  23. 服务下线后为什么还会被调用?
  24. Feign No instances available 怎么排查?
  25. Gateway 404、503、504 分别怎么排查?

本章小结

Spring Cloud 学习要按“治理问题”而不是“组件名字”推进。注册中心解决服务在哪里,Feign 解决怎么声明式调用,LoadBalancer 解决选哪台实例,Gateway 解决入口治理,Sentinel/Resilience4j 解决故障保护,配置中心解决参数治理,链路追踪解决跨服务排查。能把这些组件串成一条真实请求链路,才算真正理解 Spring Cloud。