Java深入解析篇十七之SpringCloud

Spring Cloud 微服务知识点详解

本文基于 Spring Cloud 2023.x / Spring Boot 3.2.x / Spring Cloud Alibaba 2023.x,系统讲解微服务核心组件原理与实战,配合完整可运行 Java 代码示例。


目录

  1. 微服务架构概述
  2. [Spring Cloud 生态全景](#Spring Cloud 生态全景)
  3. 服务注册与发现(Nacos/Eureka/Consul)
  4. [负载均衡(Spring Cloud LoadBalancer)](#负载均衡(Spring Cloud LoadBalancer))
  5. 服务间调用(OpenFeign/RestTemplate/WebClient)
  6. 熔断与降级(Sentinel/Resilience4j)
  7. [API 网关(Spring Cloud Gateway)](#API 网关(Spring Cloud Gateway))
  8. [配置中心(Nacos Config/Spring Cloud Config)](#配置中心(Nacos Config/Spring Cloud Config))
  9. [链路追踪(Micrometer Tracing/Zipkin)](#链路追踪(Micrometer Tracing/Zipkin))
  10. [消息驱动(Spring Cloud Stream)](#消息驱动(Spring Cloud Stream))
  11. 分布式事务(Seata)
  12. [Spring Cloud Alibaba](#Spring Cloud Alibaba)
  13. [服务网格(Service Mesh)简介](#服务网格(Service Mesh)简介)
  14. 微服务最佳实践

一、微服务架构概述

1.1 单体架构 vs 微服务架构

单体架构(Monolithic)将所有功能打包在一个部署单元中,开发简单但难以扩展和维护;微服务架构(Microservices)将系统拆分为一组围绕业务能力构建、可独立部署、独立扩展的小型服务。

维度 单体架构 微服务架构
部署 整体部署,牵一发动全身 独立部署,互不影响
扩展 只能整体扩展 按需扩展热点服务
技术栈 统一受限 每服务可异构(多语言)
复杂度 代码内部复杂 运维与分布式复杂
故障 一处崩溃可能拖垮全局 故障隔离,弹性更强
团队 协作冲突多 小团队自治(Two-Pizza Team)

1.2 微服务核心特征

java 复制代码
/**
 * 微服务设计的核心原则(示意):
 * 1. 单一职责:每个服务围绕一个业务能力(DDD 限界上下文)
 * 2. 独立部署:服务可独立构建、测试、部署
 * 3. 去中心化治理:服务自治,数据独立(Database per Service)
 * 4. 容错设计:面向失败设计(Design for Failure)
 * 5. 自动化基础设施:CI/CD、容器化、自动扩缩容
 */
public interface MicroservicePrinciple {
    // 服务边界清晰
    void singleResponsibility();
    // 独立部署与扩展
    void independentDeployment();
    // 去中心化数据管理
    void decentralizedData();
    // 面向失败设计
    void designForFailure();
}

1.3 微服务面临的挑战

微服务拆分后引入了一系列分布式系统问题,正是 Spring Cloud 生态要解决的:

  • 服务注册与发现:服务实例动态变化,如何找到对方?
  • 负载均衡:多实例间如何分配请求?
  • 服务调用:如何优雅地发起远程调用?
  • 容错:网络抖动、下游故障如何隔离?
  • 配置管理:分布式配置如何统一与动态刷新?
  • 链路追踪:一次请求跨越多个服务如何排查?
  • 数据一致性:跨服务事务如何保证?

二、Spring Cloud 生态全景

2.1 Spring Cloud 是什么

Spring Cloud 是基于 Spring Boot 的一站式微服务解决方案,它利用 Spring Boot 的开发便利性,封装了分布式系统中常见的模式(服务发现、配置、熔断、网关、追踪等),让开发者快速构建分布式系统。

2.2 版本命名与对应关系

Spring Cloud 采用伦敦地铁站命名(Dalston、Finchley、Greenwich、Hoxton、2020.0、2021.0、2022.0、2023.0...),从 2020.0 开始改用年份命名。

xml 复制代码
<!-- 父工程统一管理版本(BOM) -->
<properties>
    <java.version>17</java.version>
    <spring-boot.version>3.2.5</spring-boot.version>
    <spring-cloud.version>2023.0.1</spring-cloud.version>
    <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- Spring Boot BOM -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Spring Cloud BOM -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- Spring Cloud Alibaba BOM -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

重要:Spring Cloud、Spring Boot、Spring Cloud Alibaba 三者版本必须严格对齐,否则会出现兼容性问题。

2.3 组件演进史

功能 早期方案(已停更/维护) 当前主流方案
注册中心 Eureka / Zookeeper Nacos / Consul
负载均衡 Ribbon Spring Cloud LoadBalancer
服务调用 RestTemplate OpenFeign / WebClient
熔断器 Hystrix Sentinel / Resilience4j
网关 Zuul Spring Cloud Gateway
配置中心 Spring Cloud Config Nacos Config
链路追踪 Sleuth + Zipkin Micrometer Tracing

三、服务注册与发现(Nacos/Eureka/Consul)

3.1 核心原理

服务注册与发现是微服务的基石。服务提供者启动时向注册中心注册自己的地址(IP:Port),服务消费者从注册中心拉取可用实例列表,再通过负载均衡选择一个实例发起调用。

复制代码
┌─────────────┐   ① register    ┌──────────────┐
│  Provider   │ ──────────────→ │   Registry   │
│ (服务提供者) │   ② heartbeat   │  (注册中心)   │
└─────────────┘ ──────────────→ └──────────────┘
                                       ↑ ③ subscribe / pull
┌─────────────┐                        │
│  Consumer   │ ───────────────────────┘
│ (服务消费者) │   ④ invoke (负载均衡选实例)
└─────────────┘ ──────────────→ Provider

3.2 Nacos 注册中心实战

Nacos(Dynamic Naming and Configuration Service)是阿里开源的注册中心 + 配置中心一体化方案,是国内主流选择。

引入依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件 application.yml

yaml 复制代码
spring:
  application:
    name: order-service        # 服务名(注册到 Nacos 的标识)
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   # Nacos 服务地址
        namespace: dev                 # 命名空间(环境隔离)
        group: DEFAULT_GROUP           # 分组
        ephemeral: true                # true=临时实例(AP),false=持久实例(CP)

启动类开启服务发现

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient   // 开启服务注册与发现
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

通过 DiscoveryClient 编程式获取实例

java 复制代码
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class InstanceController {

    private final DiscoveryClient discoveryClient;

    public InstanceController(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
    }

    /**
     * 获取指定服务的所有健康实例
     */
    @GetMapping("/instances")
    public List<ServiceInstance> instances(String serviceId) {
        // 返回该服务名下所有已注册实例
        return discoveryClient.getInstances(serviceId);
    }

    /**
     * 获取所有已注册的服务名
     */
    @GetMapping("/services")
    public List<String> services() {
        return discoveryClient.getServices();
    }
}

3.3 Nacos 的 AP 与 CP

Nacos 同时支持 AP 和 CP 模型,通过实例类型切换:

  • 临时实例(ephemeral=true,默认):采用 AP 模型(Distro 协议),保证可用性。客户端通过心跳上报,心跳丢失则标记不健康,适合绝大多数业务服务。
  • 持久实例(ephemeral=false):采用 CP 模型(Raft 协议),保证一致性。实例信息持久化,不会因心跳丢失被剔除,适合 K8S 等场景。

3.4 Eureka 注册中心

Eureka 是 Netflix 开源的 AP 型注册中心,已进入维护模式(不再新增功能),但仍有大量存量系统使用。

xml 复制代码
<!-- 服务端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer   // 声明为 Eureka 服务端
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
yaml 复制代码
# Eureka Server 配置
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false   # 单节点不注册自己
    fetch-registry: false         # 单节点不拉取注册表
    service-url:
      defaultZone: http://localhost:8761/eureka/
  server:
    enable-self-preservation: true  # 自我保护机制(防雪崩)

Eureka 的自我保护机制:当短时间内大量服务心跳丢失时,Eureka 不会立即剔除实例,而是进入自我保护状态,宁可保留可能不健康的实例,也不愿误删健康实例,保证可用性(AP)。

3.5 Consul 注册中心

Consul 是 HashiCorp 开源的 CP 型注册中心,支持多数据中心、健康检查方式丰富(TCP/HTTP/脚本/TTL)。

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
yaml 复制代码
spring:
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        service-name: ${spring.application.name}
        health-check-path: /actuator/health   # 健康检查路径
        health-check-interval: 15s            # 检查间隔

3.6 三大注册中心对比

对比项 Nacos Eureka Consul
CAP AP/CP 可切换 AP CP
健康检查 心跳 + 主动探测 客户端心跳 TCP/HTTP/脚本/TTL
雪崩保护 支持(保护阈值) 支持(自我保护) 不支持
配置中心 内置 KV 存储
维护状态 活跃 维护模式 活跃
多数据中心 支持 不支持 原生支持

四、负载均衡(Spring Cloud LoadBalancer)

4.1 负载均衡分类

  • 服务端负载均衡:Nginx、F5,由独立服务器统一分发请求。
  • 客户端负载均衡:Spring Cloud LoadBalancer,由调用方在本地从实例列表中选择一个实例发起请求。

Spring Cloud LoadBalancer 是 Ribbon 的官方替代品,自 Spring Cloud 2020.0 起成为默认负载均衡器。

4.2 配合 RestTemplate 使用

java 复制代码
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    /**
     * @LoadBalanced 让 RestTemplate 具备负载均衡能力
     * 请求时可用服务名代替具体 IP:Port
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    private final RestTemplate restTemplate;

    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping("/order")
    public String createOrder(Long productId) {
        // 使用服务名 product-service 代替具体地址
        // LoadBalancer 会自动选择一个实例并替换为真实 IP:Port
        String url = "http://product-service/product/" + productId;
        return restTemplate.getForObject(url, String.class);
    }
}

4.3 配合 WebClient 使用(响应式)

java 复制代码
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}
java 复制代码
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@Service
public class ProductServiceClient {

    private final WebClient webClient;

    public ProductServiceClient(@LoadBalanced WebClient.Builder builder) {
        this.webClient = builder.build();
    }

    public Mono<String> getProduct(Long id) {
        return webClient.get()
                .uri("http://product-service/product/{id}", id)
                .retrieve()
                .bodyToMono(String.class);
    }
}

4.4 自定义负载均衡策略

默认策略为轮询(RoundRobin),可通过自定义 ReactorLoadBalancer 切换为随机或自定义逻辑。

java 复制代码
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

/**
 * 注意:此类不要加 @Configuration,避免被全局扫描
 */
public class CustomLoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // 使用随机策略替代默认轮询
        return new RandomLoadBalancer(
                factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}
java 复制代码
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Configuration;

@Configuration
// 仅对 product-service 应用自定义策略
@LoadBalancerClient(name = "product-service",
        configuration = CustomLoadBalancerConfig.class)
public class LoadBalancerConfig {
}

五、服务间调用(OpenFeign/RestTemplate/WebClient)

5.1 OpenFeign 声明式调用

OpenFeign 是声明式的 HTTP 客户端,通过接口 + 注解的方式定义远程调用,底层集成了 LoadBalancer 和熔断器,是微服务间调用的首选。

引入依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- 使用 OkHttp 作为底层 HTTP 客户端(性能更好) -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

启动类开启 Feign

java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients   // 开启 Feign 客户端扫描
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

定义 Feign 接口

java 复制代码
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * name:目标服务名(注册中心的服务名)
 * path:服务统一前缀(可选)
 * fallbackFactory:降级工厂(配合熔断器)
 */
@FeignClient(name = "product-service", path = "/product",
        fallbackFactory = ProductClientFallbackFactory.class)
public interface ProductClient {

    /**
     * 根据 ID 查询商品
     * 注解与方法签名映射到 HTTP 请求
     */
    @GetMapping("/{id}")
    ProductDTO getById(@PathVariable("id") Long id);

    /**
     * 扣减库存
     */
    @GetMapping("/stock/deduct")
    Boolean deductStock(@RequestParam("productId") Long productId,
                        @RequestParam("count") Integer count);
}

降级工厂(fallbackFactory 可获取异常信息)

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class ProductClientFallbackFactory implements FallbackFactory<ProductClient> {

    private static final Logger log = LoggerFactory.getLogger(ProductClientFallbackFactory.class);

    @Override
    public ProductClient create(Throwable cause) {
        log.error("调用 product-service 失败", cause);
        // 返回降级实现
        return new ProductClient() {
            @Override
            public ProductDTO getById(Long id) {
                return ProductDTO.defaultProduct();   // 返回兜底数据
            }

            @Override
            public Boolean deductStock(Long productId, Integer count) {
                return false;
            }
        };
    }
}

调用方使用

java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    private final ProductClient productClient;

    public OrderController(ProductClient productClient) {
        this.productClient = productClient;
    }

    @GetMapping("/order/create")
    public String createOrder(Long productId) {
        // 像调用本地方法一样调用远程服务
        ProductDTO product = productClient.getById(productId);
        productClient.deductStock(productId, 1);
        return "下单成功:" + product.getName();
    }
}

5.2 Feign 配置(超时、日志、拦截器)

yaml 复制代码
# 全局 Feign 配置
spring:
  cloud:
    openfeign:
      client:
        config:
          default:                # default 表示全局,也可指定服务名
            connect-timeout: 5000  # 连接超时 5s
            read-timeout: 10000    # 读取超时 10s
            logger-level: FULL     # 日志级别:NONE/BASIC/HEADERS/FULL
      okhttp:
        enabled: true              # 启用 OkHttp

请求拦截器(传递请求头/Token)

java 复制代码
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;

@Configuration
public class FeignConfig {

    /**
     * 将上游请求的 Authorization 头透传到下游服务
     */
    @Bean
    public RequestInterceptor authInterceptor() {
        return (RequestTemplate template) -> {
            ServletRequestAttributes attrs =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attrs != null) {
                HttpServletRequest request = attrs.getRequest();
                String token = request.getHeader("Authorization");
                if (token != null) {
                    template.header("Authorization", token);
                }
            }
        };
    }
}

5.3 RestTemplate / WebClient / gRPC 对比

方式 风格 适用场景
OpenFeign 声明式、同步 服务间 HTTP 调用(首选)
RestTemplate 编程式、同步 简单调用(维护模式,不推荐新项目)
WebClient 编程式、异步非阻塞 响应式 / WebFlux 场景
gRPC 二进制 RPC、HTTP/2 高性能、强类型、内部通信

gRPC 简介 :gRPC 基于 Protocol Buffers 序列化、HTTP/2 多路复用,性能远高于 HTTP+JSON,适合对性能敏感的内部服务通信。Spring Boot 可通过 grpc-spring-boot-starter 整合。


六、熔断与降级(Sentinel/Resilience4j)

6.1 熔断器原理

熔断器(Circuit Breaker)源于电路保险丝概念,用于防止故障在服务间蔓延(雪崩效应)。它有三种状态:

复制代码
        失败率超阈值
CLOSED ───────────────→ OPEN(直接走降级,不调用下游)
  ↑                        │
  │ 探测请求成功            │ 经过熔断时间窗
  │                        ↓
  └────────────────── HALF_OPEN(放行少量探测请求)
        探测失败 → 回到 OPEN
  • CLOSED(关闭):正常放行请求,统计失败率。
  • OPEN(打开):失败率超阈值,所有请求直接降级,不再调用下游。
  • HALF_OPEN(半开):经过一段时间窗后,放行少量探测请求,成功则恢复 CLOSED,失败则回到 OPEN。

6.2 Sentinel 实战

Sentinel 是阿里开源的流量治理组件,提供流控、熔断降级、热点限流、系统保护等能力,并配有实时监控控制台。

引入依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
yaml 复制代码
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080   # Sentinel 控制台地址
        port: 8719                  # 客户端与控制台通信端口
      eager: true                   # 启动即加载(默认懒加载)

@SentinelResource 注解使用

java 复制代码
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    /**
     * value:资源名
     * blockHandler:流控/降级时的处理方法(处理 BlockException)
     * fallback:业务异常时的降级方法
     */
    @GetMapping("/user")
    @SentinelResource(value = "getUser",
            blockHandler = "getUserBlockHandler",
            fallback = "getUserFallback")
    public User getUser(Long id) {
        if (id < 0) {
            throw new IllegalArgumentException("非法 ID");
        }
        return userService.findById(id);
    }

    /**
     * 流控/熔断触发时调用
     * 方法签名必须与原方法一致,最后可加 BlockException 参数
     */
    public User getUserBlockHandler(Long id, BlockException ex) {
        return new User(id, "系统繁忙,请稍后再试");
    }

    /**
     * 业务异常时调用
     */
    public User getUserFallback(Long id, Throwable ex) {
        return new User(id, "默认用户");
    }
}

编程式定义规则

java 复制代码
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;

import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Component
public class SentinelRuleConfig {

    @PostConstruct
    public void initRules() {
        initFlowRules();
        initDegradeRules();
    }

    /**
     * 流控规则:限制 QPS
     */
    private void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("getUser");                 // 资源名
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);  // 按 QPS 限流
        rule.setCount(100);                          // 阈值:每秒 100 次
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    /**
     * 熔断规则:慢调用比例
     */
    private void initDegradeRules() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();
        rule.setResource("getUser");
        // 慢调用比例策略
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        rule.setCount(500);          // RT 阈值 500ms
        rule.setSlowRatioThreshold(0.5);  // 慢调用比例 50%
        rule.setTimeWindow(10);      // 熔断时长 10s
        rule.setMinRequestAmount(5); // 最小请求数
        rule.setStatIntervalMs(1000);// 统计窗口
        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }
}

6.3 Resilience4j 实战

Resilience4j 是轻量级的容错库,受 Hystrix 启发但专为 Java 8+ 函数式编程设计,是 Hystrix 的官方推荐替代品。

引入依赖

xml 复制代码
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot3</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
yaml 复制代码
resilience4j:
  circuitbreaker:
    instances:
      productService:
        sliding-window-size: 10        # 滑动窗口大小
        failure-rate-threshold: 50     # 失败率阈值 50%
        wait-duration-in-open-state: 10s  # OPEN 状态持续时间
        permitted-number-of-calls-in-half-open-state: 3  # 半开探测次数
        slow-call-duration-threshold: 2s
        slow-call-rate-threshold: 100
  retry:
    instances:
      productService:
        max-attempts: 3                # 最大重试次数
        wait-duration: 1s              # 重试间隔
  timelimiter:
    instances:
      productService:
        timeout-duration: 3s           # 超时时间

注解式使用

java 复制代码
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import io.github.resilience4j.retry.annotation.Retry;
import io.github.resilience4j.timelimiter.annotation.TimeLimiter;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class ProductServiceClient {

    /**
     * 多个注解组合使用,注意执行顺序(外到内):
     * Retry > CircuitBreaker > RateLimiter > TimeLimiter > Bulkhead
     */
    @CircuitBreaker(name = "productService", fallbackMethod = "getProductFallback")
    @Retry(name = "productService")
    @TimeLimiter(name = "productService")
    public CompletableFuture<ProductDTO> getProduct(Long id) {
        return CompletableFuture.supplyAsync(() -> {
            // 调用远程服务
            return restTemplate.getForObject(
                    "http://product-service/product/" + id, ProductDTO.class);
        });
    }

    /**
     * 降级方法:签名需兼容(多一个 Throwable 参数)
     */
    public CompletableFuture<ProductDTO> getProductFallback(Long id, Throwable t) {
        return CompletableFuture.completedFuture(ProductDTO.defaultProduct());
    }
}

6.4 Sentinel vs Resilience4j

对比项 Sentinel Resilience4j
隔离方式 信号量隔离 信号量 / 线程池(Bulkhead)
控制台 提供实时监控控制台 无(可整合 Actuator)
流控 丰富(QPS/线程/关联/链路) RateLimiter
规则配置 动态(控制台/持久化) 配置文件为主
适用 国内、需要可视化治理 轻量、函数式、国际化

七、API 网关(Spring Cloud Gateway)

7.1 网关的作用

API 网关是系统的统一入口,承担路由转发、鉴权、限流、日志、协议转换等横切关注点,避免每个微服务重复实现。

Spring Cloud Gateway 基于 Spring WebFlux(Netty)构建,采用非阻塞异步模型,性能优于基于 Servlet 的 Zuul 1.x。

7.2 三大核心概念

  • Route(路由):网关的基本单元,由 ID、目标 URI、断言集合、过滤器集合组成。
  • Predicate(断言):匹配条件,决定请求是否走该路由。
  • Filter(过滤器):对请求/响应进行加工。

7.3 引入依赖与基础配置

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 网关也注册到 Nacos,实现动态路由 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
yaml 复制代码
spring:
  application:
    name: gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true            # 开启从注册中心动态创建路由
          lower-case-service-id: true
      routes:
        - id: product-route        # 路由 ID
          uri: lb://product-service # lb:// 表示负载均衡到该服务
          predicates:
            - Path=/product/**     # 匹配路径
          filters:
            - StripPrefix=0        # 去掉前缀层数
        - id: order-route
          uri: lb://order-service
          predicates:
            - Path=/order/**
            - Method=GET,POST      # 多断言组合(AND 关系)

7.4 常用 Predicate

yaml 复制代码
predicates:
  - Path=/api/**                       # 路径匹配
  - Method=GET,POST                    # 请求方法
  - Header=X-Token, \d+                # 请求头(正则)
  - Query=name, abc                    # 请求参数
  - After=2024-01-01T00:00:00+08:00[Asia/Shanghai]   # 时间之后
  - Before=2025-01-01T00:00:00+08:00[Asia/Shanghai]  # 时间之前
  - Cookie=sessionId, [0-9]+           # Cookie
  - Host=**.example.com                # 主机名

7.5 自定义全局过滤器(统一鉴权)

java 复制代码
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 全局过滤器:统一鉴权
 * GlobalFilter 对所有路由生效
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    // 白名单路径
    private final List<String> whiteList = List.of(
            "/product/public/**", "/user/login");

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 白名单直接放行
        if (whiteList.stream().anyMatch(p -> pathMatcher.match(p, path))) {
            return chain.filter(exchange);
        }

        // 校验 Token
        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || token.isEmpty()) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();   // 终止请求
        }

        // TODO: 校验 token 有效性,并将用户信息放入请求头透传
        return chain.filter(exchange);
    }

    /**
     * 过滤器执行顺序,值越小优先级越高
     */
    @Override
    public int getOrder() {
        return -1;
    }
}

7.6 网关限流(RequestRateLimiter)

基于 Redis + Lua 的令牌桶算法限流:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
java 复制代码
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;

@Configuration
public class RateLimiterConfig {

    /**
     * 按客户端 IP 限流
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
                exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }
}
yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: product-route
          uri: lb://product-service
          predicates:
            - Path=/product/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒填充令牌数
                redis-rate-limiter.burstCapacity: 20   # 桶容量
                key-resolver: "#{@ipKeyResolver}"      # 限流维度

八、配置中心(Nacos Config/Spring Cloud Config)

8.1 为什么需要配置中心

微服务实例众多,配置散落在各服务中难以管理。配置中心实现配置集中管理、动态刷新、环境隔离、版本回滚。

8.2 Nacos Config 实战

引入依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Spring Cloud 2020+ 需要 bootstrap 支持 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

bootstrap.yml(优先于 application.yml 加载)

yaml 复制代码
spring:
  application:
    name: order-service
  profiles:
    active: dev
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: dev-namespace-id     # 命名空间 ID(环境隔离)
        group: DEFAULT_GROUP            # 分组
        file-extension: yaml            # 配置文件格式
        # Data ID 自动拼接为:order-service-dev.yaml

Data ID 规范${spring.application.name}-${spring.profiles.active}.${file-extension},例如 order-service-dev.yaml

动态刷新配置

java 复制代码
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @RefreshScope 标注的 Bean,配置变更时会重新创建,
 * 从而读取到最新配置值
 */
@RestController
@RefreshScope
public class ConfigController {

    @Value("${order.discount:1.0}")
    private double discount;

    @GetMapping("/discount")
    public double getDiscount() {
        return discount;   // Nacos 修改配置后自动刷新
    }
}

使用 @ConfigurationProperties 绑定

java 复制代码
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Component
@RefreshScope
@ConfigurationProperties(prefix = "order")
public class OrderProperties {
    private double discount;
    private int maxAmount;
    private String notice;

    // getter / setter 省略
}

8.3 Nacos 配置监听(原生 API)

java 复制代码
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;

import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class NacosConfigListenerDemo {

    public static void main(String[] args) throws Exception {
        Properties props = new Properties();
        props.put("serverAddr", "127.0.0.1:8848");
        ConfigService configService = NacosFactory.createConfigService(props);

        String dataId = "order-service-dev.yaml";
        String group = "DEFAULT_GROUP";

        // 获取配置
        String content = configService.getConfig(dataId, group, 5000);
        System.out.println("当前配置:" + content);

        // 注册监听器,配置变更时回调(基于长轮询)
        configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor() {
                return Executors.newSingleThreadExecutor();
            }

            @Override
            public void receiveConfigInfo(String configInfo) {
                System.out.println("配置变更:" + configInfo);
            }
        });
    }
}

8.4 Spring Cloud Config

Spring Cloud Config 由 Config Server(配置服务端,通常以 Git 为后端)和 Config Client 组成。

xml 复制代码
<!-- Config Server -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
java 复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
yaml 复制代码
# Config Server 配置(Git 后端)
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/xxx/config-repo.git
          username: xxx
          password: xxx
          search-paths: '{application}'   # 按服务名查找目录

Config Client 动态刷新需配合 @RefreshScope 并调用 /actuator/refresh 端点;批量刷新可借助 Spring Cloud Bus(基于 MQ 广播刷新事件)。

8.5 Nacos Config vs Spring Cloud Config

对比项 Nacos Config Spring Cloud Config
动态刷新 原生支持(长轮询) 需 @RefreshScope + Bus
配置后端 内置数据库 Git/SVN/本地
控制台 提供可视化管理
灰度发布 支持 不支持
学习成本 中(需搭 Git + Bus)

九、链路追踪(Micrometer Tracing/Zipkin)

9.1 分布式追踪原理

一次请求跨越多个服务,需要一种机制将整条调用链串联起来。核心概念:

  • Trace :一次完整的请求链路,由唯一的 traceId 标识。

  • Span :链路中的一个工作单元(如一次 RPC、一次 DB 查询),有 spanIdparentId,表达调用树关系。

  • TraceContext :通过 HTTP 头(W3C traceparent / B3)在服务间传播 traceId。

    Trace (traceId=abc123)
    ├── Span: gateway spanId=1
    │ ├── Span: order-svc spanId=2 parentId=1
    │ │ └── Span: DB spanId=3 parentId=2
    │ └── Span: product-svc spanId=4 parentId=1

9.2 Micrometer Tracing 实战

自 Spring Cloud 2022.0 起,Sleuth 被移除,链路追踪统一由 Micrometer Tracing 提供门面,桥接到 Brave 或 OpenTelemetry。

引入依赖(OpenTelemetry + Zipkin 上报)

xml 复制代码
<!-- Micrometer Tracing 门面 -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<!-- OpenTelemetry Zipkin 上报 -->
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
<!-- Actuator 暴露追踪端点 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
yaml 复制代码
management:
  tracing:
    sampling:
      probability: 1.0          # 采样率 1.0 = 100%(生产建议调低)
  zipkin:
    tracing:
      endpoint: http://127.0.0.1:9411/api/v2/spans   # Zipkin 上报地址
logging:
  pattern:
    # 日志中打印 traceId 和 spanId,便于关联日志与链路
    level: "%5p [${spring.application.name},%X{traceId:-},%X{spanId:-}]"

配置完成后,OpenFeign、RestTemplate、WebClient、Gateway 等会自动传播 traceId,无需手动编码。

9.3 编程式创建 Span

java 复制代码
import io.micrometer.tracing.Span;
import io.micrometer.tracing.Tracer;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final Tracer tracer;

    public OrderService(Tracer tracer) {
        this.tracer = tracer;
    }

    public void createOrder(Long productId) {
        // 手动创建一个 Span 标记一段业务逻辑
        Span span = tracer.nextSpan().name("create-order-business").start();
        try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
            // 添加业务标签,便于在 Zipkin 中检索
            span.tag("productId", String.valueOf(productId));
            // ... 业务逻辑
            doBusiness();
        } catch (Exception e) {
            span.error(e);   // 记录异常
            throw e;
        } finally {
            span.end();      // 必须结束 Span
        }
    }

    private void doBusiness() {
        // 获取当前 traceId 写入业务日志/数据库
        String traceId = tracer.currentSpan().context().traceId();
        System.out.println("当前 traceId:" + traceId);
    }
}

9.4 后端展示

  • Zipkin:轻量级,提供 Web UI 查看调用链、耗时分析。
  • Jaeger:CNCF 项目,云原生友好。
  • SkyWalking:国产 APM,功能全面(追踪 + 指标 + 告警),Java 探针无侵入。

十、消息驱动(Spring Cloud Stream)

10.1 核心思想

Spring Cloud Stream 提供消息驱动的编程模型,通过 Binder(绑定器) 屏蔽底层 MQ(Kafka/RabbitMQ/RocketMQ)的差异,让业务代码与具体消息中间件解耦。

核心抽象:

  • Binder:连接应用与 MQ 的中间层。
  • Binding:应用输入/输出通道与 MQ 目的地的桥梁。
  • 函数式编程模型 (新版推荐):用 Function/Consumer/Supplier Bean 定义消息处理逻辑。

10.2 引入依赖

xml 复制代码
<!-- Kafka Binder(也可换 rabbit / rocketmq) -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-stream-binder-kafka</artifactId>
</dependency>

10.3 函数式消息生产与消费

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.function.Consumer;
import java.util.function.Supplier;

@Configuration
public class MessageConfig {

    /**
     * 消费者:监听消息
     * Bean 名称 orderConsumer 对应 binding 名 orderConsumer-in-0
     */
    @Bean
    public Consumer<OrderEvent> orderConsumer() {
        return event -> {
            System.out.println("收到订单事件:" + event);
            // 处理业务逻辑
        };
    }

    /**
     * 生产者:定时/按需产出消息(此处演示 Supplier)
     */
    @Bean
    public Supplier<OrderEvent> orderProducer() {
        return () -> new OrderEvent(System.currentTimeMillis(), "PRODUCED");
    }
}

编程式发送消息(StreamBridge)

java 复制代码
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {

    private final StreamBridge streamBridge;

    public OrderController(StreamBridge streamBridge) {
        this.streamBridge = streamBridge;
    }

    @PostMapping("/order")
    public String createOrder() {
        OrderEvent event = new OrderEvent(System.currentTimeMillis(), "CREATED");
        // 第一个参数为输出 binding 名,第二个为消息体
        boolean success = streamBridge.send("orderProducer-out-0", event);
        return success ? "发送成功" : "发送失败";
    }
}

配置 binding 与目的地

yaml 复制代码
spring:
  cloud:
    function:
      definition: orderConsumer;orderProducer   # 声明启用的函数 Bean
    stream:
      bindings:
        orderConsumer-in-0:
          destination: order-topic              # MQ 中的 topic/queue
          group: order-group                    # 消费组(组内竞争消费)
        orderProducer-out-0:
          destination: order-topic
      kafka:
        binder:
          brokers: 127.0.0.1:9092

10.4 高级特性

  • 消费组(Consumer Group):同一组的多个实例竞争消费,避免重复处理。
  • 分区(Partitioning):相同特征的消息路由到同一分区,保证顺序。
  • 错误处理:消费失败可重试,最终进入死信队列(DLQ)。

十一、分布式事务(Seata)

11.1 分布式事务问题

微服务下每个服务有独立数据库(Database per Service),一个业务操作可能跨多个服务和数据库,本地事务无法保证全局一致性。

经典理论:

  • CAP:一致性(C)、可用性(A)、分区容错(P)三者最多取二。
  • BASE:基本可用(Basically Available)、软状态(Soft state)、最终一致(Eventually consistent)。

11.2 Seata 架构与角色

Seata 是阿里开源的分布式事务解决方案,包含三大角色:

  • TC(Transaction Coordinator):事务协调器,独立部署的 Server,维护全局和分支事务状态。
  • TM(Transaction Manager):事务管理器,定义全局事务范围,开启/提交/回滚全局事务。
  • RM(Resource Manager):资源管理器,管理分支事务资源,向 TC 注册分支并上报状态。

11.3 Seata 四种模式

模式 一致性 性能 业务侵入 适用场景
AT 最终一致 无侵入 大多数 OLTP 场景(首选)
TCC 最终一致 高(需写三方法) 高性能、需自定义补偿
SAGA 最终一致 长事务、流程编排
XA 强一致 无侵入 强一致要求场景

11.4 AT 模式原理

AT(Auto Transaction)模式是最常用的无侵入模式:

复制代码
一阶段(执行):
  1. 解析业务 SQL
  2. 查询前镜像(before image)
  3. 执行业务 SQL
  4. 查询后镜像(after image)
  5. 生成 undo_log 并插入
  6. 本地事务提交(业务数据 + undo_log 一起提交)
  7. 向 TC 注册分支事务

二阶段(提交):
  异步删除 undo_log(快速完成)

二阶段(回滚):
  1. 用 undo_log 的 before image 校验脏写
  2. 用 before image 反向补偿,恢复数据
  3. 删除 undo_log

11.5 Seata 实战

引入依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
yaml 复制代码
seata:
  enabled: true
  application-id: ${spring.application.name}
  tx-service-group: my_tx_group              # 事务分组
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
  config:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      group: SEATA_GROUP
  service:
    vgroup-mapping:
      my_tx_group: default                   # 分组映射到 TC 集群

前置条件 :每个参与事务的数据库需创建 undo_log 表(AT 模式):

sql 复制代码
CREATE TABLE IF NOT EXISTS `undo_log` (
    `branch_id`     BIGINT       NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal, 1:defense',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB COMMENT = 'AT transaction mode undo table';

开启全局事务

java 复制代码
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    private final OrderMapper orderMapper;
    private final ProductClient productClient;   // Feign 调用商品服务
    private final AccountClient accountClient;   // Feign 调用账户服务

    public OrderService(OrderMapper orderMapper,
                        ProductClient productClient,
                        AccountClient accountClient) {
        this.orderMapper = orderMapper;
        this.productClient = productClient;
        this.accountClient = accountClient;
    }

    /**
     * @GlobalTransactional 开启全局事务
     * 任一分支失败,所有分支自动回滚
     * name:全局事务名(可选)
     * rollbackFor:触发回滚的异常类型
     */
    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public void createOrder(OrderDTO dto) {
        // ① 本地:创建订单(RM 分支事务)
        orderMapper.insert(dto);

        // ② 远程:扣减库存(商品服务的分支事务)
        productClient.deductStock(dto.getProductId(), dto.getCount());

        // ③ 远程:扣减余额(账户服务的分支事务)
        accountClient.deductBalance(dto.getUserId(), dto.getAmount());

        // 任一步抛异常 → TC 通知所有 RM 回滚
    }
}

注意:Seata 通过拦截 Feign/RestTemplate 请求,在请求头中传播全局事务 ID(XID),使远程服务自动加入同一全局事务。


十二、Spring Cloud Alibaba

12.1 简介

Spring Cloud Alibaba 是阿里开源的一站式微服务解决方案,将阿里多年微服务实践(Nacos、Sentinel、Seata、RocketMQ 等)整合进 Spring Cloud 生态,是国内微服务落地的事实标准。

12.2 核心组件

组件 功能
Nacos 服务注册发现 + 配置中心
Sentinel 流量控制 + 熔断降级
Seata 分布式事务
RocketMQ 消息驱动 + 事件总线
Dubbo 高性能 RPC(可整合)
OSS 阿里云对象存储

12.3 典型架构组合

一个完整的 Spring Cloud Alibaba 微服务系统通常包含:

复制代码
客户端
  │
  ↓
Spring Cloud Gateway(网关:路由/鉴权/限流)
  │
  ├─→ 服务 A ──┐
  ├─→ 服务 B ──┼──→ Nacos(注册 + 配置)
  └─→ 服务 C ──┘
       │
       ├─ OpenFeign(服务间调用)
       ├─ Sentinel(熔断限流)
       ├─ Seata(分布式事务)
       ├─ RocketMQ(异步解耦)
       └─ Micrometer Tracing + SkyWalking(链路追踪)

12.4 版本选择建议

  • 新项目优先选择 Spring Cloud Alibaba(活跃维护、生态完善、中文文档友好)。
  • 严格遵循官方版本对应关系,避免组件冲突。
  • 关注 Spring Boot 3.x / JDK 17+ 的迁移(javax → jakarta 命名空间变化)。

十三、服务网格(Service Mesh)简介

13.1 什么是服务网格

服务网格(Service Mesh)是处理服务间通信的基础设施层。它将服务治理能力(负载均衡、熔断、限流、追踪、mTLS)从业务代码中剥离,下沉到独立的代理进程中,实现业务零侵入。

13.2 架构:数据平面 + 控制平面

复制代码
┌──────────────────────────────────────────┐
│           控制平面(Control Plane)         │
│        Istio / Pilot(策略下发、管理)       │
└───────────────┬──────────────────────────┘
                │ 下发配置
   ┌────────────┼────────────┐
   ↓            ↓            ↓
┌──────┐    ┌──────┐    ┌──────┐
│Svc A │    │Svc B │    │Svc C │  ← 数据平面
│+Envoy│←──→│+Envoy│←──→│+Envoy│   (Sidecar 代理)
└──────┘    └──────┘    └──────┘
  • 数据平面(Data Plane):由 Sidecar 代理(如 Envoy)组成,每个服务实例旁部署一个代理,所有进出流量经代理处理。
  • 控制平面(Control Plane):如 Istio,负责管理和配置代理,下发流量策略、安全策略。

13.3 Service Mesh vs Spring Cloud

对比项 Spring Cloud Service Mesh
治理方式 SDK 侵入业务代码 Sidecar 代理,业务零侵入
语言支持 主要 Java 多语言友好
升级成本 升级 SDK 需重新部署业务 升级代理即可,业务无感
性能 无额外网络跳转 多一跳 Sidecar,有性能损耗
复杂度 应用层复杂 基础设施层复杂(运维要求高)
成熟度 Java 生态成熟 云原生趋势,逐步成熟

13.4 代表实现

  • Istio + Envoy:业界事实标准,功能全面。
  • Linkerd:轻量级,Rust 编写的数据平面。

服务网格是云原生时代的重要演进方向,常与 Kubernetes 结合使用。Spring Cloud 与 Service Mesh 并非互斥,可混合使用。


十四、微服务最佳实践

14.1 服务拆分

  • 按业务领域(DDD 限界上下文)拆分,而非按技术层。
  • 避免过度拆分,服务粒度适中(一个团队可维护)。
  • 遵循"高内聚、低耦合",服务间通过明确的 API 契约通信。

14.2 容错设计(面向失败设计)

java 复制代码
/**
 * 远程调用容错三件套:超时 + 熔断 + 降级
 * 任何远程调用都必须配置,缺一不可
 */
@FeignClient(name = "product-service",
        fallbackFactory = ProductClientFallbackFactory.class)  // 降级
public interface ProductClient {
    // 配合配置:connect-timeout / read-timeout(超时)
    // 配合 Sentinel / Resilience4j(熔断)
    @GetMapping("/{id}")
    ProductDTO getById(@PathVariable("id") Long id);
}
  • 超时:所有远程调用必须设置合理超时,避免线程被无限阻塞。
  • 熔断:下游故障时快速失败,防止雪崩。
  • 降级:返回兜底数据或友好提示,保证核心链路可用。
  • 隔离:舱壁模式(线程池/信号量)隔离不同服务调用,互不影响。

14.3 幂等性设计

写操作(创建、扣减)必须保证幂等,防止网络重试导致重复执行:

java 复制代码
import org.springframework.stereotype.Service;

@Service
public class PaymentService {

    private final PaymentMapper paymentMapper;

    /**
     * 通过唯一业务键保证幂等
     * 同一 orderId 重复请求只处理一次
     */
    public void pay(String orderId, BigDecimal amount) {
        // 方案一:数据库唯一键约束
        // 方案二:先查询是否已处理
        Payment existing = paymentMapper.selectByOrderId(orderId);
        if (existing != null) {
            return;   // 已处理,直接返回(幂等)
        }
        // 方案三:分布式锁 / Token 机制
        paymentMapper.insert(new Payment(orderId, amount));
    }
}

14.4 可观测性三位一体

  • Logging(日志):结构化日志,携带 traceId 便于关联。
  • Metrics(指标):Spring Boot Actuator + Micrometer + Prometheus + Grafana。
  • Tracing(追踪):Micrometer Tracing + Zipkin/SkyWalking。
yaml 复制代码
# 暴露 Actuator 监控端点
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  endpoint:
    health:
      show-details: always

14.5 配置与安全

  • 敏感配置(密码、密钥)加密存储,不入代码库。
  • 用 Namespace/Profile 隔离开发/测试/生产环境。
  • 网关层统一鉴权,服务间调用透传身份。

14.6 数据一致性策略选择

场景 推荐方案
强一致、低并发 Seata AT / XA
高并发、可异步 消息最终一致(RocketMQ 事务消息)
长流程业务 Seata SAGA
高性能、自定义补偿 Seata TCC

优先选择最终一致性方案(性能高、可用性强),仅在必要时使用强一致。

14.7 部署与运维

  • 容器化部署(Docker + Kubernetes),支持自动扩缩容。
  • 服务无状态设计,状态外置到 Redis/DB,便于水平扩展。
  • 完善的 CI/CD 流水线,灰度发布、蓝绿部署降低风险。
  • 健康检查(/actuator/health)配合 K8s 探针实现自愈。

14.8 常见面试要点回顾

复制代码
1. Nacos AP/CP 如何切换?
   → 临时实例(默认)=AP(Distro),持久实例=CP(Raft)

2. Sentinel 与 Hystrix 区别?
   → Sentinel 信号量隔离+控制台;Hystrix 线程池隔离(已停更)

3. Gateway 与 Zuul 区别?
   → Gateway 基于 WebFlux 非阻塞,性能更高

4. Seata AT 模式原理?
   → 一阶段拦截 SQL 生成 undo_log 本地提交;
     二阶段成功删 undo_log,失败反向补偿

5. Feign 如何传递 traceId / Token?
   → Micrometer Tracing 自动注入 traceparent 头;
     Token 通过 RequestInterceptor 透传

6. 配置动态刷新原理?
   → Nacos 长轮询感知变更 + @RefreshScope 重建 Bean

7. 如何防止服务雪崩?
   → 超时 + 熔断 + 降级 + 隔离 + 限流

总结

Spring Cloud 微服务体系围绕分布式系统的核心挑战,提供了完整的解决方案:

挑战 解决方案
服务寻址 Nacos / Eureka / Consul
流量分配 Spring Cloud LoadBalancer
服务调用 OpenFeign / WebClient / gRPC
故障隔离 Sentinel / Resilience4j
统一入口 Spring Cloud Gateway
配置管理 Nacos Config / Spring Cloud Config
链路排查 Micrometer Tracing + Zipkin/SkyWalking
异步解耦 Spring Cloud Stream
数据一致 Seata

掌握这些组件的原理与协作关系,并结合最佳实践(容错、幂等、可观测性),才能构建高可用、易维护的微服务系统。

相关推荐
是未才2 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
ttod_qzstudio3 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
萧瑟余晖4 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring
离陌在学C#6 小时前
C# 重载与重写:深入理解面向对象编程的核心概念
java·c#
洛阳泰山6 小时前
AI 应用层被 Python 卷成红海,为什么我偏要用 Java 造一个 RAG + 工作流引擎?
java·人工智能·后端
二十雨辰7 小时前
[Java]-Spring面试题
java·开发语言
老马历写记7 小时前
Maven POM 依赖管理总结
java·maven·system·pom·optional
古法安卓7 小时前
Android-车机 GNSS 定位数据接收问题排查
android·java·android studio
_oP_i7 小时前
python 后缀 mjs文件
开发语言·python