Spring Cloud 微服务核心组件学习笔记

一、Eureka ------ 服务注册与发现

1.1 什么是服务注册与发现

Spring Cloud封装了Netflix开发的Eureka模块来实现服务治理。在微服务架构中,服务实例的IP和端口是动态变化的,传统静态配置方式完全失效。服务注册发现机制通过三大核心能力解决这一挑战:动态感知(新实例自动注册、故障实例自动剔除)、位置透明(服务消费者无需关注提供者物理位置)、负载均衡(结合客户端负载均衡算法智能分配请求流量)。

Eureka采用C/S架构设计,Eureka Server作为服务注册功能的服务器(即服务注册中心),系统中的其他微服务使用Eureka客户端连接到Eureka Server并维持心跳连接。

1.2 核心工作机制

  • 服务注册:各个微服务节点启动后,会在Eureka Server中进行注册,Eureka Server的服务注册表中存储所有可用服务节点的信息。

  • 心跳续约:Eureka客户端在应用启动后向Eureka Server发送心跳,默认周期为30秒。

  • 服务剔除:如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳(默认90秒),会将该服务节点从注册表中移除。

  • 自我保护机制:当网络异常时自动进入保护状态,避免因心跳超时误删健康实例。当Eureka Server检测到大量服务实例失去联系时,不会立即移除它们,而是保留注册信息,防止误判。

1.3 关键配置

服务端配置(Eureka Server):

复制代码
eureka:
  server:
    enable-self-preservation: false  # 关闭自我保护模式(生产环境建议开启)
    eviction-interval-timer-in-ms: 5000  # 清理间隔

客户端配置(Eureka Client):

复制代码
eureka:
  instance:
    lease-renewal-interval-in-seconds: 15  # 心跳间隔
  client:
    service-url:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8761/eureka/
    register-with-eureka: true
    fetch-registry: true

依赖引入:

复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

服务端启动类添加 @EnableEurekaServer 注解。

客户端启动类添加@EnableDiscoveryClient

1.4 高可用部署

Eureka Server采用Peer-to-Peer对等架构,推荐至少部署3个节点构成高可用集群。多个Eureka Server之间相互注册,实现注册表数据同步,防止单点故障。

二、Ribbon ------ 多实例负载均衡

2.1 什么是Ribbon

Ribbon是Netflix开源的项目,主要功能是提供客户端的软件负载均衡算法和服务调用。与Nginx这种服务端负载均衡不同,Ribbon属于进程内负载均衡------将负载均衡逻辑集成到消费方,消费方从服务注册中心获知可用地址,然后自己选择合适服务器。Ribbon在工作时分两步:先选择Eureka Server(优先选择同一区域内负载较少的server),再根据用户指定的策略从服务注册列表中选择一个地址。

2.2 内置负载均衡策略

Ribbon提供了多种内置负载均衡策略:

策略 说明 适用场景
轮询(RoundRobinRule) 按顺序循环分配请求 实例性能均等的场景
随机(RandomRule) 随机选择服务实例 避免热点问题
重试(RetryRule) 在指定时间内重试失败请求 需要自动恢复的场景
区域感知(ZoneAvoidanceRule) 结合实例所在区域调度,优先同区域 降低网络延迟
响应时间加权(WeightedResponseTimeRule) 根据响应时间动态调整权重 自动规避高延迟实例

2.3 关键配置

复制代码
order-service:  # 针对特定服务配置
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule
    ConnectTimeout: 500  # 连接超时(默认1000ms)
    ReadTimeout: 3000    # 读取超时(默认1000ms)
    MaxAutoRetries: 1    # 同一实例重试次数
    MaxAutoRetriesNextServer: 1  # 切换实例重试次数

2.4 使用方式

通过 @LoadBalanced 注解注入RestTemplate,Ribbon会自动拦截请求,根据服务ID从注册中心查找实例列表:

复制代码
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

三、Spring Cloud Gateway ------ 统一入口网关

3.1 什么是Gateway

Spring Cloud Gateway是Spring Cloud生态中的新一代API网关组件,基于Spring Framework 5、Project Reactor和Spring Boot构建,采用响应式编程模型,底层使用Netty作为通信框架。相比Zuul 1.x,Gateway的吞吐量可达其3-5倍,平均延迟降低60%以上。

API网关作为所有外部请求的统一入口,承担着路由转发、安全认证、流量控制、监控日志等关键职责。

3.2 三大核心概念

Gateway引入了路由(Route)、断言(Predicate)和过滤器(Filter)三个核心概念:

  • 路由(Route) :网关的基本构建块,包含目标URI、断言集合和过滤器链三个关键要素。

  • 断言(Predicate) :匹配条件,支持Path、Header、Cookie等20+种路由条件。

  • 过滤器(Filter) :分为前置过滤器(业务执行前)和后置过滤器(业务执行后),可实现鉴权、限流、日志等横切关注点。

3.3 基础路由配置

复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service  # lb:// 表示启用负载均衡
          predicates:
            - Path=/api/users/**
          filters:
            - StripPrefix=1  # 移除首层路径前缀
  • id:路由唯一标识

  • uri:目标服务地址,lb://前缀表示启用负载均衡

  • predicates:断言条件集合

  • filters:过滤器链(按声明顺序执行)

3.4 与Eureka集成实现服务发现

Gateway可以配置为基于服务注册中心自动创建路由:

复制代码
spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  # 开启基于服务发现的路由定位

四、OpenFeign ------ 服务远程调用

4.1 什么是OpenFeign

OpenFeign是一个声明式的HTTP客户端框架,最初由Netflix开发,现已成为Spring Cloud生态的核心组件。它的核心价值在于将HTTP请求抽象为Java接口方法,通过注解驱动实现服务间通信。

声明式编程与命令式编程的本质区别:命令式编程需要详细描述"如何做"的每一个步骤(手动拼接URL、设置请求头、解析响应等),而声明式编程只关注"做什么",底层通信由框架自动处理。

4.2 基本用法

复制代码
@FeignClient(name = "order-service")
public interface OrderClient {
    @GetMapping("/orders/{id}")
    Order getOrderById(@PathVariable("id") Long id);
    
    @PostMapping("/orders")
    Order createOrder(@RequestBody OrderDTO orderDTO);
}

当配置url属性时,OpenFeign直接使用固定地址;若省略该属性,则通过服务名从注册中心获取可用实例列表。

4.3 负载均衡集成

OpenFeign的负载均衡能力通过与Spring Cloud LoadBalancer集成实现。实例选择流程:

  1. 从注册中心拉取服务实例元数据(IP、端口、健康状态)

  2. 根据配置的负载均衡策略(默认轮询)选择目标实例

  3. 动态构建请求URL

4.4 关键配置

复制代码
feign:
  client:
    config:
      default:
        connectTimeout: 5000   # 连接超时
        readTimeout: 3000      # 读取超时
        loadbalancer:
          strategy: roundRobin  # 轮询(默认),可选random、retry等

4.5 编码优势对比

特性 OpenFeign RestTemplate
代码量 接口定义+注解(5-10行) 手动构造请求(20-30行)
可维护性 接口变更自动适配 需同步修改调用代码
测试友好性 可直接mock接口 需模拟HTTP响应

五、Resilience4j ------ 服务熔断与降级

5.1 什么是Resilience4j

Resilience4j是Hystrix的替代方案,是一个轻量级的服务容错框架,具有"原生整合Spring Boot、无多余依赖、功能全面、配置灵活"的优势。核心提供重试、熔断、降级、限流、舱壁五大能力。

在分布式体系中,服务间的依赖关系可能导致雪崩效应------某个服务响应过慢或不可用,导致上游服务占用越来越多资源,最终整个系统崩溃。断路器的作用就是当故障发生时"跳闸",避免故障蔓延。

5.2 断路器(Circuit Breaker)状态机

断路器有三种状态:

  • Closed(关闭) :正常状态,请求正常通过

  • Open(打开) :熔断触发,直接返回降级结果,不发起实际调用

  • Half-Open(半开) :经过冷却时间后,允许部分试探请求,检测服务是否恢复

5.3 熔断与降级配置

复制代码
spring:
  cloud:
    circuitbreaker:
      resilience4j:
        circuitbreaker:
          configs:
            default:
              failureRateThreshold: 50  # 故障率阈值50%
              waitDurationInOpenState: 5s  # 断路器打开持续时间
              slidingWindowType: COUNT_BASED  # 滑动窗口类型
              slidingWindowSize: 100  # 滑动窗口大小
              minimumNumberOfCalls: 20  # 计算故障率前最少调用次数
              permittedNumberOfCallsInHalfOpenState: 10  # 半开状态允许的调用数
              automaticTransitionFromOpenToHalfOpenEnabled: true

5.4 限流(Rate Limiter)配置

复制代码
resilience4j:
  ratelimiter:
    configs:
      default:
        limitForPeriod: 10  # 每个时间段允许的最大请求数
        limitRefreshPeriod: 1s  # 刷新时间周期
        timeoutDuration: 0s  # 获取许可证的等待时间(0s表示不等待)

5.5 代码中使用

复制代码
@Service
public class MyService {
    @CircuitBreaker(name = "myService", fallbackMethod = "fallback")
    public String doSomething() {
        // 业务逻辑
    }
    
    public String fallback(Throwable t) {
        return "服务繁忙,请稍后重试";  // 降级返回友好提示
    }
}

通过 @CircuitBreaker@Retry@RateLimiter@TimeLimiter@Bulkhead 等注解将容错策略应用到方法上,并通过fallbackMethod指定降级逻辑。

六、组件协作全景图

一个完整的微服务请求链路如下:

复制代码
外部请求 → Spring Cloud Gateway(路由+限流)
         ↓
   服务消费者(OpenFeign声明式调用 + Ribbon负载均衡)
         ↓
   服务提供者(注册到Eureka)
         ↓
   Resilience4j(熔断/降级保护)

各组件职责分工:

  • Eureka:服务注册中心,管理所有服务实例的注册信息

  • Ribbon:客户端负载均衡,在服务调用时选择合适的实例

  • Gateway:统一入口,路由转发、限流、鉴权

  • OpenFeign:声明式远程调用,简化服务间HTTP通信

  • Resilience4j:服务容错,熔断、降级、限流保护

Gateway与Resilience4j组合是主流方案,同时建议在服务层也做本地熔断,避免网关层面成为瓶颈。

所遇到的问题

1、 项目依赖与版本兼容

现象
  • 启动时出现 GatewayClassPathWarningAutoConfigurationspring-cloud-starter-gateway is deprecated 警告。

  • IDE 中某些类(如 RateLimitException)无法导入,显示红色。

原因

Spring Cloud Gateway 从 4.x 起(对应 Spring Boot 3.x)重构了模块,将核心内容拆分为 spring-cloud-gateway-server-webfluxspring-cloud-starter-gateway-server-webflux。旧模块已被弃用,将在下一个大版本移除。

解决方案(正确依赖配置)

在父 POM 或子模块的 pom.xml 中,只保留新依赖,不要同时引入新旧两个:

复制代码
<!-- 推荐:只引入这一个 Starter -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway-server-webflux</artifactId>
</dependency>
<!-- 如果需要 Eureka 客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 负载均衡(Gateway 默认依赖) -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Redis Reactive(限流必须) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、Gateway 配置迁移(弃用警告)

现象
复制代码
Property source 'application.yaml':
  Key: spring.cloud.gateway.routes[0].id → Replacement: spring.cloud.gateway.server.webflux.routes[0].id
  ...
原因

配置属性的根路径从 spring.cloud.gateway 迁移到 spring.cloud.gateway.server.webflux

解决方案(正确配置格式)

yaml

复制代码
spring:
  cloud:
    gateway:
      server:
        webflux:
          routes:
            - id: user-service
              uri: lb://USER-SERVICE   # 使用服务名进行负载均衡
              predicates:
                - Path=/api/user/**
              filters:
                - name: RequestRateLimiter
                  args:
                    key-resolver: "#{@ipKeyResolver}"
                    redis-rate-limiter.replenishRate: 10
                    redis-rate-limiter.burstCapacity: 20

注意 :缩进必须正确,routeswebflux 对齐(2 空格),列表项缩进 2 空格。

3、LoadBalancer下划线异常

现象

该异常是由于 Spring Cloud 的 LoadBalancerInterceptor 在解析请求 URI 时,通过 URI.getHost() 获取服务名,但得到的值为 null,从而触发了断言失败。

原因

  • URI http://USER53558_CLIENT2/hello 中的主机名 USER53558_CLIENT2 包含下划线 _

  • 尽管 java.net.URI 在较新版本(Java 8+)中通常允许下划线,但在某些 Java 版本或特定的运行环境中,URI.getHost() 可能因为主机名不符合 DNS 命名规范而返回 null(尤其当 URIparseServerAuthority() 被隐式或显式调用时)。

  • Spring Cloud 的 LoadBalancerInterceptor 直接使用 URI.getHost() 来提取服务名,当结果为 null 时就会抛出此异常。

4、Jackson 反序列化失败(无法构造实例)

现象

复制代码
feign.codec.DecodeException: Type definition error: [simple type, class com.example.user53558_test.domain.entiry.User]
...
Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Cannot construct instance of `com.example.user53558_test.domain.entiry.User` 
(no Creators, like default constructor, exist): cannot deserialize from Object value

原因

  • Feign 默认使用 Jackson 将远程服务返回的 JSON 反序列化为 Java 对象。

  • Jackson 在反序列化时,需要能够创建目标类的实例。

  • 默认情况下,Jackson 通过 无参构造方法(public 或 protected)来创建对象,然后通过 setter 或字段赋值。

  • 如果类中没有无参构造,且未提供 @JsonCreator 标注的带参构造,则抛出上述异常。

5、Resilience4j Fallback 方法匹配失败

现象

复制代码
WARN  ... FallbackExecutor : No fallback method match found
java.lang.NoSuchMethodException: interface java.util.List 
class com.example.user53558_test.Service.impl.imageserviceimpl.fallbackHandler(int,class java.lang.Throwable)

原因

  • imageserviceimpl 中使用了 @CircuitBreaker 注解并指定了 fallbackMethod = "fallbackHandler"

  • Resilience4j 在触发熔断或异常时,通过反射调用 fallback 方法。

  • 反射要求方法签名(方法名、参数类型、返回值)完全匹配

  • 错误提示 NoSuchMethodException,说明找不到符合签名 fallbackHandler(int, Throwable) 的方法,返回值类型期望为 List

解决方式:

  • Resilience4j 的 fallback 方法必须与原始方法在同一类 中,且为 public

  • 参数顺序:先原方法的全部参数,再可选的 Throwable(可放在最后)。

  • 如果方法返回 List,fallback 也必须返回 List,不能返回 Object 或其他类型。

相关推荐
欢醉2 天前
一次P0 故障:微服务线程数莫名暴涨 10 倍,线程问题踩坑
springboot·线程·springcloud
振宇i5 天前
springcloudAlibaba2025.0.0.0组件版本对应关系
springcloud·mybatis-plus·依赖关系
地瓜伯伯1 个月前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
星辰_mya1 个月前
openfeign之在回首
java·架构·dubbo·springcloud·openfeign
苏渡苇2 个月前
Seata 番外篇:使用 docker-compose 部署 Seata Server(TC)及 K8S 部署 Seata 高可用
spring boot·docker·微服务·容器·kubernetes·seata·springcloud
牧羊狼的狼2 个月前
springcloud 各中间件集群部署形态说明
springcloud·集群部署
DN金猿2 个月前
spring.cloud.nacos.discovery.server-addr和spring.cloud.nacos.server-addr区别
java·开发语言·nacos·springcloud·sca
DN金猿2 个月前
SpringCloudAlibaba微服务启动报错
微服务·云原生·nacos·架构·springcloud·sca
JAVA坚守者2 个月前
Tomcat 多微服务部署:启动顺序 + JVM 调优实战
springcloud·jvm调优·权限问题·tomcat8.5·外置tomcat部署·启动顺序控制