目录
正在加载目录…
专栏文章
专栏文章
Spring Cloud 系列
1. Spring Cloud:微服务组件与治理实践

Spring Cloud:微服务组件与治理实践

发布于 2026-05-26 09:44 · 最后编辑于 2026-07-31 15:53 · 字数 3,301 👁 78 次阅读

本文系统梳理 Spring Cloud 微服务全家桶的核心组件——注册中心、配置中心、网关、熔断限流、负载均衡、声明式调用、链路追踪,帮助你快速掌握微服务架构的工程实践。

目录

章节说明
微服务核心组件全景各组件的职责与选型
注册中心:Eureka vs Nacos两代注册中心对比
负载均衡:Ribbon vs LoadBalancer客户端负载均衡演进
OpenFeign 声明式客户端动态代理原理与实战
配置中心:Spring Cloud Config vs Nacos Config配置动态刷新
熔断降级:Sentinel内外兼修的服务容错
微服务网关:Gateway vs Zuul路由、谓词、过滤器
链路追踪:Sleuth + ZipkinTraceId / SpanId 原理

微服务核心组件全景

Spring Cloud 是专为微服务架构设计的"全家桶"框架,与 Spring Boot 分工协作:

  • Spring Boot:主内,处理底层柴米油盐(数据访问、RESTful、日志、容器)
  • Spring Cloud:主外,提供分布式系统支持(服务发现、配置管理、网关、熔断)

../../../assets/01 Spring Cloud 微服务/file 20260605123839493

核心组件一览

功能Netflix 组件(旧)Spring Cloud Alibaba(新)Spring 原生
注册中心EurekaNacos-
配置中心Spring Cloud ConfigNacos Config-
负载均衡Ribbon(维护中)-Spring Cloud LoadBalancer
熔断降级Hystrix(维护中)SentinelResilience4j
服务调用Feign(旧)-OpenFeign
网关Zuul 1.x-Spring Cloud Gateway
链路追踪--Sleuth + Zipkin
消息驱动-RocketMQSpring Cloud Stream
分布式事务-Seata-

选型建议:新项目优先选用 Spring Cloud Alibaba 组件(Nacos + Sentinel)+ Spring 原生组件(Gateway + LoadBalancer + OpenFeign),避开已进入维护状态的 Netflix 组件(Hystrix、Ribbon)。

../../../assets/01 Spring Cloud 微服务/file 20260605123839040

注册中心:Eureka vs Nacos

为什么需要注册中心

微服务集群中服务实例的 IP 动态变化,调用方需要通过注册中心实时获取可用节点列表。

核心机制

Provider 启动 → 向注册中心注册(服务名 + IP:Port + 健康状态)
Consumer 启动 → 订阅注册中心 → 缓存节点列表到本地
节点变更      → 注册中心推送变更给所有订阅方

Eureka vs Nacos 对比

维度EurekaNacos
一致性模型AP(最终一致)支持 AP 和 CP,默认 AP
健康检查客户端心跳(30s)客户端心跳 + 服务端主动探测
服务下线感知慢(心跳超时 90s)快(主动推送)
配置中心不支持内置支持
维护状态2.0 计划搁浅,1.x 维护中活跃维护,持续迭代
控制台基础 UI功能完整的管理控制台
多数据中心有限支持原生支持

Nacos 注册示例

# application.yml
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev          # 命名空间隔离
        group: DEFAULT_GROUP
// 启动类开启服务发现
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

负载均衡:Ribbon vs LoadBalancer

Spring Cloud 的负载均衡是客户端负载均衡:Consumer 从注册中心获取所有 Provider 节点列表,在本地自主选择节点发起调用,不依赖外部负载均衡设备。

Ribbon vs Spring Cloud LoadBalancer

维度Ribbon(旧)Spring Cloud LoadBalancer(新)
维护状态进入维护,不推荐新项目使用Spring 官方维护,活跃迭代
响应式支持不支持支持 WebFlux
策略扩展通过 IRule 扩展通过 ReactorLoadBalancer 扩展
默认策略轮询轮询

自定义负载均衡策略(金丝雀测试示例)

// com.example — 自定义负载均衡策略,将带有 canary=true 标签的请求路由到灰度节点
@Bean
public ReactorLoadBalancer<ServiceInstance> canaryLoadBalancer(
        Environment environment,
        LoadBalancerClientFactory factory) {
    String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    return new CanaryLoadBalancer(
        factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}

public class CanaryLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        // 检查请求头中是否有 canary 标记
        HttpHeaders headers = ((RequestDataContext) request.getContext())
            .getClientRequest().getHeaders();
        boolean isCanary = "true".equals(headers.getFirst("X-Canary"));

        return serviceInstanceListSupplierProvider.getIfAvailable()
            .get(request)
            .next()
            .map(instances -> selectInstance(instances, isCanary));
    }

    private Response<ServiceInstance> selectInstance(
            List<ServiceInstance> instances, boolean isCanary) {
        List<ServiceInstance> targets = instances.stream()
            .filter(i -> isCanary == "true".equals(i.getMetadata().get("canary")))
            .collect(Collectors.toList());

        if (targets.isEmpty()) targets = instances;
        return new DefaultResponse(targets.get(ThreadLocalRandom.current()
            .nextInt(targets.size())));
    }
}

OpenFeign 声明式客户端

OpenFeign 通过动态代理将接口调用转化为远程 HTTP 调用,让服务间调用像调用本地方法一样简单。

动态代理原理

启动阶段:
  @EnableFeignClients → 扫包加载所有 @FeignClient 接口
  FeignClientsRegistrar → 构造 FeignClientFactoryBean
  ReflectiveFeign → 解析注解元数据,生成 MethodHandler
  → 创建实现 InvocationHandler 的动态代理对象,注入 Spring 容器

运行阶段:
  业务代码调用 FeignClient 接口方法
  → 动态代理拦截
  → 根据 MethodHandler 中的元数据构建 HTTP Request
  → 通过 LoadBalancer 选择目标节点
  → 发起远程 HTTP 调用
  → 反序列化响应,返回结果

基础使用

// 定义 FeignClient 接口(com.example)
@FeignClient(
    value = "order-service",          // 服务名(与注册中心一致)
    fallback = OrderServiceFallback.class  // 降级实现
)
public interface OrderServiceClient {

    @GetMapping("/orders/{orderId}")
    OrderResponse getOrder(@PathVariable("orderId") Long orderId);

    @PostMapping("/orders")
    OrderResponse createOrder(@RequestBody CreateOrderRequest request);

    @GetMapping("/orders")
    List<OrderResponse> listOrders(
        @RequestParam("userId") Long userId,
        @RequestParam(value = "page", defaultValue = "0") int page
    );
}

// 降级实现
@Component
public class OrderServiceFallback implements OrderServiceClient {
    @Override
    public OrderResponse getOrder(Long orderId) {
        return OrderResponse.empty();  // 返回默认值
    }

    @Override
    public OrderResponse createOrder(CreateOrderRequest request) {
        throw new ServiceUnavailableException("订单服务暂不可用");
    }

    @Override
    public List<OrderResponse> listOrders(Long userId, int page) {
        return Collections.emptyList();
    }
}

高级配置

# application.yml
feign:
  client:
    config:
      order-service:           # 针对特定服务的配置
        connect-timeout: 1000  # 连接超时(ms)
        read-timeout: 5000     # 读取超时(ms)
        logger-level: FULL     # 日志级别:NONE/BASIC/HEADERS/FULL
  compression:
    request:
      enabled: true            # 开启请求压缩
      min-request-size: 2048
    response:
      enabled: true            # 开启响应压缩
// 自定义 FeignClient 配置
@Configuration
public class FeignConfig {
    // 自定义请求拦截器(如添加认证 Token)
    @Bean
    public RequestInterceptor authInterceptor() {
        return template -> {
            String token = SecurityContextHolder.getToken();
            template.header("Authorization", "Bearer " + token);
        };
    }

    // 自定义重试策略
    @Bean
    public Retryer feignRetryer() {
        // 初始间隔 100ms,最大间隔 1s,最多重试 3 次
        return new Retryer.Default(100, 1000, 3);
    }
}

配置中心:Spring Cloud Config vs Nacos Config

为什么需要配置中心

微服务数量多,配置分散在各服务中,难以统一管理;配置变更需要重启服务,影响可用性。

配置中心解决:

  • 配置集中管理(一处修改,全局生效)
  • 动态刷新(不重启服务即可更新配置)
  • 环境隔离(dev/test/prod 不同配置)
  • 版本管理和回滚

Spring Cloud Config vs Nacos Config

维度Spring Cloud ConfigNacos Config
存储后端Git 仓库(主)/ 本地文件内置数据库(MySQL)
动态刷新需配合 Spring Cloud Bus + MQ原生支持,长轮询推送
配置格式properties / yaml / jsonproperties / yaml / json / text
命名空间通过 profile 区分原生命名空间 + Group
控制台无(依赖 Git UI)完整管理控制台
维护活跃度维护中活跃迭代

Nacos Config 使用示例

# bootstrap.yml(必须在 bootstrap 中配置,先于 application.yml 加载)
spring:
  application:
    name: user-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        namespace: dev
        group: DEFAULT_GROUP
        file-extension: yaml     # 配置文件格式
        # 加载多个配置文件
        extension-configs:
          - data-id: common.yaml
            group: COMMON_GROUP
            refresh: true
// 动态刷新配置(com.example)
@RestController
@RefreshScope  // 标注此注解,配置变更后自动刷新
public class UserController {

    @Value("${user.max-page-size:20}")
    private int maxPageSize;

    @GetMapping("/users")
    public List<User> listUsers(@RequestParam int size) {
        int actualSize = Math.min(size, maxPageSize);
        return userService.list(actualSize);
    }
}

熔断降级:Sentinel

服务雪崩与容错思路

服务雪崩:下游服务故障(如慢 SQL 导致响应超时),请求积压,依赖该服务的所有上游服务被拖垮,整个集群崩溃。

Sentinel 的"内外兼修"容错思路

外部流量控制(限流)
  ↓ 拦截超量请求,保护服务入口
内部异常治理(降级 + 熔断)
  ↓ 隔离下游故障,防止级联传播

降级 vs 熔断

概念触发条件效果
降级(Fallback)单次调用发生异常/超时执行降级逻辑(返回默认值/忽略异常)
熔断(Circuit Breaker)异常比例/慢调用比例超过阈值,窗口内降级次数达到阈值一段时间内停止调用下游,所有请求直接走降级逻辑

熔断状态机

关闭(Closed)
  ↓ 异常比例超阈值
打开(Open)—— 所有请求直接降级
  ↓ 休眠时间窗口结束
半开(Half-Open)—— 放行少量探测请求
  ↓ 探测成功 → 关闭;探测失败 → 重新打开

Sentinel 流控规则

// 编程方式定义流控规则(com.example)
@PostConstruct
public void initSentinelRules() {
    // 限流规则:QPS 不超过 100
    List<FlowRule> flowRules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    rule.setResource("getUserById");    // 资源名(接口/方法名)
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(100);                 // QPS 阈值
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT); // 快速失败
    flowRules.add(rule);
    FlowRuleManager.loadRules(flowRules);

    // 熔断规则:慢调用比例超过 50% 触发熔断
    List<DegradeRule> degradeRules = new ArrayList<>();
    DegradeRule degradeRule = new DegradeRule();
    degradeRule.setResource("getUserById");
    degradeRule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType());
    degradeRule.setCount(0.5);          // 慢调用比例阈值 50%
    degradeRule.setSlowRatioThreshold(0.5);
    degradeRule.setTimeWindow(10);      // 熔断时长 10s
    degradeRules.add(degradeRule);
    DegradeRuleManager.loadRules(degradeRules);
}

与 OpenFeign 集成

feign:
  sentinel:
    enabled: true
@FeignClient(value = "order-service", fallbackFactory = OrderFallbackFactory.class)
public interface OrderServiceClient {
    @GetMapping("/orders/{id}")
    OrderResponse getOrder(@PathVariable Long id);
}

@Component
public class OrderFallbackFactory implements FallbackFactory<OrderServiceClient> {
    @Override
    public OrderServiceClient create(Throwable cause) {
        return orderId -> {
            log.error("调用订单服务失败: {}", cause.getMessage());
            return OrderResponse.builder().status("UNAVAILABLE").build();
        };
    }
}

Resilience4j(Spring 原生替代方案)

// com.example — Resilience4j 熔断器示例
@Service
public class UserService {

    @CircuitBreaker(name = "userService", fallbackMethod = "getUserFallback")
    @RateLimiter(name = "userService")
    @Retry(name = "userService")
    public UserResponse getUser(Long userId) {
        return externalUserApi.getUser(userId);
    }

    public UserResponse getUserFallback(Long userId, Exception e) {
        log.warn("熔断触发,返回默认用户: userId={}", userId);
        return UserResponse.defaultUser(userId);
    }
}
resilience4j:
  circuitbreaker:
    instances:
      userService:
        failure-rate-threshold: 50        # 失败率 50% 触发熔断
        wait-duration-in-open-state: 10s  # 熔断持续 10s
        sliding-window-size: 10           # 滑动窗口大小

微服务网关:Gateway vs Zuul

Gateway vs Zuul 对比

维度Spring Cloud GatewayZuul 1.x
底层模型基于 Netty 的异步非阻塞基于 Servlet 的同步阻塞
性能高(Reactor 模型)相对低(线程池模型)
Spring 支持Spring 官方推荐逐渐淡出 Spring Cloud
WebFlux 支持原生支持不支持
过滤器GlobalFilter + GatewayFilterZuulFilter

结论:新项目统一使用 Spring Cloud Gateway,Zuul 仅用于维护旧系统。

Gateway 核心概念

Route(路由)
  ├── ID:路由唯一标识
  ├── URI:目标服务地址(可以是服务名,如 lb://order-service)
  ├── Predicate(谓词):路由匹配规则,满足所有谓词才转发
  └── Filter(过滤器):请求/响应处理链

路由配置示例

# application.yml
spring:
  cloud:
    gateway:
      routes:
        # 路由到用户服务
        - id: user-service-route
          uri: lb://user-service        # lb:// 表示通过注册中心做负载均衡
          predicates:
            - Path=/api/users/**        # 路径匹配
            - Method=GET,POST           # 方法匹配
            - Header=X-Version, v2      # Header 匹配
          filters:
            - StripPrefix=1             # 去掉路径前缀 /api
            - AddRequestHeader=X-Gateway-Source, gateway
            - name: RequestRateLimiter  # 限流过滤器
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20

        # 限时秒杀路由(只在特定时间段生效)
        - id: flash-sale-route
          uri: lb://order-service
          predicates:
            - Path=/api/flash-sale/**
            - Between=2024-11-11T00:00:00+08:00, 2024-11-11T23:59:59+08:00
          order: 1                      # 优先级(数字越小优先级越高)

自定义全局过滤器

// com.example — 全局鉴权过滤器
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("Authorization");

        if (isPublicPath(request.getPath().value())) {
            return chain.filter(exchange);  // 白名单路径直接放行
        }

        if (token == null || !jwtUtils.validate(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 将用户信息传递给下游服务
        String userId = jwtUtils.getUserId(token);
        ServerHttpRequest mutatedRequest = request.mutate()
            .header("X-User-Id", userId)
            .build();
        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }

    @Override
    public int getOrder() {
        return -100;  // 负数表示高优先级,在其他过滤器之前执行
    }
}

全局跨域配置

// com.example — 全局 CORS 配置
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOriginPattern("*");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

链路追踪:Sleuth + Zipkin

为什么需要链路追踪

微服务架构中,一次用户请求会经过多个服务,出现 Bug 时难以定位是哪个服务出了问题。链路追踪通过为每次请求生成全局唯一 ID,将所有相关日志串联起来。

Sleuth 核心概念

概念说明
Trace一次完整的请求调用链,由全局唯一的 Trace ID 标识
Span调用链中的一个基本工作单元(如一次 HTTP 调用、一次 DB 查询)
Span ID当前 Span 的唯一 ID
Parent Span ID父级 Span 的 ID,通过此字段串联调用顺序

日志示例

# 格式:[服务名, TraceId, SpanId, 是否上报Zipkin]
INFO [user-service, a1b2c3d4e5f6, a1b2c3d4e5f6, true] 收到请求 GET /users/123
INFO [order-service, a1b2c3d4e5f6, f1e2d3c4b5a6, true] 查询用户订单
INFO [payment-service, a1b2c3d4e5f6, 1a2b3c4d5e6f, true] 处理支付

调用链示意

用户请求
  │ Trace ID: a1b2c3
  │
  ├── user-service (Span: A1, Parent: null)
  │     │
  │     ├── order-service (Span: B2, Parent: A1)
  │     │     │
  │     │     └── payment-service (Span: C3, Parent: B2)
  │     │
  │     └── inventory-service (Span: B3, Parent: A1)

Sleuth 四种事件(Annotation)

事件缩写含义
Client Sendcs客户端发送请求
Server Receivesr服务端收到请求
Server Sendss服务端发送响应
Client Receivecr客户端收到响应

时延计算

  • 服务端处理时间 = ss - sr
  • 网络延迟 = sr - cs(或 cr - ss)
  • 总耗时 = cr - cs

集成配置

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
# application.yml
spring:
  zipkin:
    base-url: http://localhost:9411  # Zipkin Server 地址
    sender:
      type: web                      # 通过 HTTP 上报(也可用 Kafka/RabbitMQ)
  sleuth:
    sampler:
      probability: 1.0               # 采样率:1.0 = 100%(生产环境建议 0.1)

完整链路追踪方案

微服务日志(含 TraceId/SpanId)
  ↓ Logback/Log4j2 输出
  ↓
ELK Stack(日志收集与检索)
  ├── Logstash:收集和解析日志
  ├── Elasticsearch:存储和索引日志
  └── Kibana:日志查询 UI

Zipkin(调用链可视化)
  ├── 收集 Span 数据
  ├── 展示调用链瀑布图
  └── 统计各服务耗时

排查流程

  1. 用户反馈报错 → 从前端日志/用户行为获取大致时间范围
  2. 在 Kibana 中搜索该时间段的 ERROR 日志 → 获取 Trace ID
  3. 在 Zipkin 中输入 Trace ID → 查看完整调用链和各节点耗时
  4. 定位到出错的服务和 Span → 在 Kibana 中搜索该服务的详细日志

参考资料

  • 《Spring Cloud 微服务项目实战》— 极客时间,姚秋辰
  • Spring Cloud 官方文档:https://spring.io/projects/spring-cloud
  • Spring Cloud Alibaba:https://github.com/alibaba/spring-cloud-alibaba
  • Sentinel 官方文档:https://sentinelguard.io/zh-cn/
  • Zipkin 官方文档:https://zipkin.io/
← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论