跳转至

Spring Cloud微服务

🎯 学习目标

学习时间:3-4周 | 难度:⭐⭐⭐⭐⭐ 高级

完成本章学习后,你将能够: - 掌握Spring Cloud Alibaba生态核心组件(Nacos/Sentinel/Seata/RocketMQ) - 理解服务注册与发现机制,能对比Nacos vs Consul vs Eureka - 熟练使用Spring Cloud Gateway构建微服务网关 - 使用Spring Cloud LoadBalancer实现客户端负载均衡 - 掌握Nacos Config与Apollo动态配置中心 - 使用Sentinel实现熔断降级与热点参数限流 - 理解Seata分布式事务的AT/TCC/Saga模式 - 集成OpenTelemetry/Jaeger/SkyWalking实现全链路追踪 - 使用Spring Cloud Stream整合RocketMQ/Kafka消息驱动 - 掌握微服务Docker Compose编排与K8s部署策略

Spring Cloud Alibaba微服务拓扑图


📖 目录

  1. Spring Cloud Alibaba生态概览
  2. 服务注册与发现
  3. 服务网关
  4. 负载均衡
  5. 配置中心
  6. 熔断降级
  7. 分布式事务
  8. 链路追踪
  9. 消息驱动
  10. 微服务部署
  11. 面试题

1. Spring Cloud Alibaba生态概览

1.1 微服务架构演进

从单体应用到微服务架构,是大规模系统的必然演进:

Text Only
单体架构 → SOA → 微服务 → 云原生(Service Mesh / Serverless)

微服务核心原则: - 单一职责:每个服务只做一件事 - 自治性:独立开发、部署、扩展 - 去中心化:数据、治理去中心化 - 弹性设计:容错、限流、降级

1.2 Spring Cloud Alibaba版本选型

Spring Cloud Alibaba是Spring Cloud的中国最佳实践,提供一站式微服务解决方案。

XML
<!-- pom.xml 版本依赖管理 -->
<properties>
    <spring-boot.version>3.2.4</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 Cloud -->
        <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 -->
        <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>

1.3 核心组件矩阵

功能域 Spring Cloud Alibaba Spring Cloud Netflix(已停更)
服务注册发现 Nacos Eureka
配置中心 Nacos Config Spring Cloud Config
熔断降级 Sentinel Hystrix
分布式事务 Seata
消息驱动 RocketMQ
服务网关 Spring Cloud Gateway Zuul
负载均衡 Spring Cloud LoadBalancer Ribbon

1.4 多模块项目结构

Text Only
microservice-demo/
├── pom.xml                          # 父POM(版本管理)
├── common/                          # 公共模块(DTO、工具类)
│   └── pom.xml
├── gateway/                         # 网关服务
│   └── pom.xml
├── user-service/                    # 用户服务
│   └── pom.xml
├── order-service/                   # 订单服务
│   └── pom.xml
├── product-service/                 # 商品服务
│   └── pom.xml
└── docker-compose.yml               # 容器编排

2. 服务注册与发现

2.1 Nacos注册中心

Nacos(Dynamic Naming and Configuration Service)是阿里巴巴开源的服务注册与配置管理平台。

引入依赖:

XML
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件:

YAML
# application.yml
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: dev            # 命名空间隔离环境
        group: DEFAULT_GROUP
        cluster-name: BJ          # 集群名(就近访问)
        weight: 1                 # 权重(负载均衡)
        metadata:
          version: v1
          env: dev

server:
  port: 8081

启动类:

Java
@SpringBootApplication
@EnableDiscoveryClient  // Spring Cloud标准注解,兼容多种注册中心
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

服务间调用(OpenFeign):

Java
// ============ 声明式Feign客户端 ============
@FeignClient(name = "product-service", fallbackFactory = ProductClientFallback.class)
public interface ProductClient {

    @GetMapping("/api/products/{id}")
    ProductDTO getProduct(@PathVariable("id") Long id);

    @GetMapping("/api/products/batch")
    List<ProductDTO> batchGetProducts(@RequestParam("ids") List<Long> ids);
}

// ============ 降级工厂 ============
@Component
public class ProductClientFallback implements FallbackFactory<ProductClient> {
    @Override
    public ProductClient create(Throwable cause) {
        return new ProductClient() {
            @Override
            public ProductDTO getProduct(Long id) {
                // 降级逻辑:返回兜底数据
                return ProductDTO.builder()
                    .id(id)
                    .name("降级商品")
                    .price(BigDecimal.ZERO)
                    .build();
            }

            @Override
            public List<ProductDTO> batchGetProducts(List<Long> ids) {
                return Collections.emptyList();
            }
        };
    }
}

2.2 Nacos vs Consul vs Eureka对比

特性 Nacos Consul Eureka
CAP模型 AP / CP可切换 CP AP
健康检查 TCP/HTTP/MySQL/自定义 TCP/HTTP/gRPC/脚本 心跳(客户端)
雪崩保护 ✅ 有 ❌ 无 ✅ 自我保护模式
配置中心 ✅ 内置 ✅ KV Store ❌ 无
多数据中心 ✅ 支持 ✅ 原生支持 ❌ 有限
Watch机制 长轮询 + Push 长轮询 短轮询
一致性协议 Raft(CP)/ Distro(AP) Raft
Spring Cloud集成 非常好 好(已停更)
适用场景 国内微服务首选 多语言/多DC 遗留项目

Nacos AP/CP切换:

Java
// 临时实例(AP模式,默认)— 适合微服务
// 心跳上报,Nacos不主动检查,注册快速
spring.cloud.nacos.discovery.ephemeral=true

// 持久实例(CP模式)— 适合基础设施服务(如数据库代理)
// Nacos主动健康检查,适合不能主动上报心跳的服务
spring.cloud.nacos.discovery.ephemeral=false

2.3 Nacos集群部署

YAML
# nacos/conf/cluster.conf
192.168.1.10:8848
192.168.1.11:8848
192.168.1.12:8848

# 使用MySQL做持久化存储(替代内嵌Derby)
# nacos/conf/application.properties
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8
db.user=nacos
db.password=nacos

3. 服务网关

3.1 Spring Cloud Gateway基础

Spring Cloud Gateway是Spring Cloud官方推荐的API网关,基于WebFlux(响应式编程)构建,性能优于Zuul 1.x。

核心概念: - Route(路由):网关的基本构建块,包含ID、目标URI、谓词集合、过滤器集合 - Predicate(谓词):匹配HTTP请求的条件(路径、Header、参数等) - Filter(过滤器):对请求/响应进行修改

XML
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

3.2 路由配置

YAML
# gateway-service application.yml
spring:
  cloud:
    gateway:
      # ===== 路由规则 =====
      routes:
        # 用户服务
        - id: user-service
          uri: lb://user-service          # lb:// 表示从注册中心获取地址
          predicates:
            - Path=/api/users/**          # 路径匹配
            - Method=GET,POST             # HTTP方法
          filters:
            - StripPrefix=1               # 去掉前缀 /api
            - AddRequestHeader=X-Gateway, true

        # 订单服务 — 带权重路由(灰度发布)
        - id: order-service-v1
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
            - Weight=group1, 90           # 90%流量
          metadata:
            version: v1

        - id: order-service-v2
          uri: lb://order-service-v2
          predicates:
            - Path=/api/orders/**
            - Weight=group1, 10           # 10%流量(灰度)
          metadata:
            version: v2

      # ===== 全局默认过滤器 =====
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Origin
        - AddResponseHeader=X-Response-Time, ${response.time}

3.3 自定义全局过滤器

Java
/**
 * JWT鉴权全局过滤器
 */
@Component
@Order(-1)  // 优先级最高
public class AuthGlobalFilter implements GlobalFilter {

    private static final List<String> WHITE_LIST = List.of(
        "/api/auth/login",
        "/api/auth/register",
        "/api/products/public"
    );

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

        // 白名单放行
        if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
            return chain.filter(exchange);
        }

        // 提取Token
        String token = request.getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            return unauthorized(exchange, "Missing or invalid token");
        }

        // 验证Token
        try {
            String jwt = token.substring(7);
            Claims claims = JwtUtil.parseToken(jwt);
            String userId = claims.getSubject();

            // 将用户信息传递给下游服务
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", userId)
                .header("X-User-Role", claims.get("role", String.class))
                .build();

            return chain.filter(exchange.mutate().request(mutatedRequest).build());
        } catch (ExpiredJwtException e) {
            return unauthorized(exchange, "Token expired");
        } catch (Exception e) {
            return unauthorized(exchange, "Invalid token");
        }
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        String body = """
            {"code": 401, "message": "%s"}
            """.formatted(message);
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }
}

3.4 网关限流

Java
/**
 * 基于Redis的请求速率限流
 */
@Configuration
public class RateLimitConfig {

    /**
     * 按IP限流的KeyResolver
     */
    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(
            Objects.requireNonNull(exchange.getRequest().getRemoteAddress())
                .getAddress().getHostAddress()
        );
    }
}
YAML
# 网关限流配置
spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/orders/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100   # 每秒100个令牌
                redis-rate-limiter.burstCapacity: 200    # 令牌桶容量200
                redis-rate-limiter.requestedTokens: 1    # 每个请求消耗1个令牌
                key-resolver: "#{@ipKeyResolver}"

4. 负载均衡

4.1 Spring Cloud LoadBalancer

Spring Cloud LoadBalancer取代了已弃用的Netflix Ribbon,提供客户端负载均衡能力。

XML
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

4.2 负载均衡策略

Java
/**
 * 自定义负载均衡配置
 * 注意:不要添加 @Configuration,避免被全局扫描
 */
public class CustomLoadBalancerConfig {

    /**
     * 轮询策略(默认)
     */
    @Bean
    public ReactorLoadBalancer<ServiceInstance> roundRobinLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RoundRobinLoadBalancer(
            loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name
        );
    }

    /**
     * 随机策略
     */
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
            loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name
        );
    }
}

// ============ 指定服务使用特定负载均衡策略 ============
@Configuration
@LoadBalancerClients({
    @LoadBalancerClient(name = "user-service", configuration = CustomLoadBalancerConfig.class),
    @LoadBalancerClient(name = "order-service", configuration = CustomLoadBalancerConfig.class)
})
public class LoadBalancerAutoConfig {
}

4.3 基于Nacos权重的负载均衡

Java
/**
 * Nacos权重负载均衡器 — 结合Nacos控制台动态调权
 */
public class NacosWeightLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final ObjectProvider<ServiceInstanceListSupplier> supplierProvider;

    public NacosWeightLoadBalancer(
            ObjectProvider<ServiceInstanceListSupplier> supplierProvider,
            String serviceId) {
        this.supplierProvider = supplierProvider;
        this.serviceId = serviceId;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        return supplierProvider.getIfAvailable()
            .get()
            .next()
            .map(this::selectByWeight);
    }

    private Response<ServiceInstance> selectByWeight(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            return new EmptyResponse();
        }

        // 使用Nacos权重进行随机选择
        List<Pair<ServiceInstance, Double>> weightedInstances = instances.stream()
            .map(inst -> {
                double weight = Double.parseDouble(
                    inst.getMetadata().getOrDefault("nacos.weight", "1.0"));
                return Pair.of(inst, weight);
            })
            .toList();

        double totalWeight = weightedInstances.stream()
            .mapToDouble(Pair::getRight).sum();
        double random = ThreadLocalRandom.current().nextDouble(totalWeight);

        double cumulative = 0;
        for (Pair<ServiceInstance, Double> pair : weightedInstances) {
            cumulative += pair.getRight();
            if (random < cumulative) {
                return new DefaultResponse(pair.getLeft());
            }
        }
        return new DefaultResponse(instances.get(0));
    }
}

5. 配置中心

5.1 Nacos Config

Nacos不仅是注册中心,也是强大的配置中心,支持动态配置刷新

XML
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Spring Cloud 2023.x 需要引入 bootstrap -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
YAML
# bootstrap.yml(优先于application.yml加载)
spring:
  application:
    name: order-service
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: dev
        group: DEFAULT_GROUP
        file-extension: yaml           # 配置格式
        # 共享配置:多服务共用的配置
        shared-configs:
          - data-id: common-database.yaml
            group: SHARED_GROUP
            refresh: true
          - data-id: common-redis.yaml
            group: SHARED_GROUP
            refresh: true
        # 扩展配置
        extension-configs:
          - data-id: order-datasource.yaml
            group: DEFAULT_GROUP
            refresh: true

5.2 动态配置刷新

Java
/**
 * 动态配置示例:降级开关、限流阈值等运行时可调整参数
 */
@Component
@RefreshScope  // Spring Cloud原生注解,配置变更时重新创建Bean
public class DynamicConfigProperties {

    @Value("${order.max-amount:99999}")
    private BigDecimal maxOrderAmount;

    @Value("${feature.toggle.new-checkout:false}")
    private boolean newCheckoutEnabled;

    @Value("${rate-limit.qps:100}")
    private int rateLimitQps;

    // Getters ...
    public BigDecimal getMaxOrderAmount() { return maxOrderAmount; }
    public boolean isNewCheckoutEnabled() { return newCheckoutEnabled; }
    public int getRateLimitQps() { return rateLimitQps; }
}

/**
 * 也可以使用 @ConfigurationProperties 方式
 */
@Component
@ConfigurationProperties(prefix = "order")
@RefreshScope
public class OrderConfig {
    private BigDecimal maxAmount;
    private int timeout;
    private RetryConfig retry;

    @Data
    public static class RetryConfig {
        private int maxRetries;
        private long delay;
    }

    // Getters & Setters ...
}

5.3 Nacos Config vs Apollo对比

特性 Nacos Config Apollo
配置格式 Properties/YAML/JSON/XML Properties/YAML/JSON/XML
实时推送 ✅ 长轮询(1s内) ✅ 推拉结合(1s内)
灰度发布 ✅ 支持 ✅ 支持(更强)
权限管理 基础 ✅ 细粒度(项目/命名空间)
版本回滚 ✅ 支持 ✅ 支持(更完善)
多环境 命名空间隔离 环境 + 集群
部署复杂度 低(单一组件) 较高(Portal + Admin + Config)
适用场景 配置+注册一体化 大规模配置管理

5.4 配置加密

Java
/**
 * 敏感配置加密 — 结合Jasypt
 */
// 1. 引入依赖
// com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5

// 2. 配置
// jasypt.encryptor.password=your-secret-key

// 3. 加密值使用 ENC() 包裹
// spring.datasource.password=ENC(加密后的密文)

@Configuration
public class JasyptConfig {
    @Bean("jasyptStringEncryptor")
    public StringEncryptor stringEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(System.getenv("JASYPT_PASSWORD")); // 从环境变量获取密钥
        config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
        config.setKeyObtentionIterations("1000");
        config.setPoolSize("1");
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        encryptor.setConfig(config);
        return encryptor;
    }
}

6. 熔断降级

6.1 Sentinel核心概念

Sentinel是阿里巴巴开源的流量治理组件,面向分布式服务架构的流量控制、熔断降级、系统负载保护。

XML
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel Dashboard数据源持久化到Nacos -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
YAML
spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080     # Sentinel Dashboard地址
        port: 8719                      # 与Dashboard通信端口
      # 规则持久化到Nacos
      datasource:
        flow:
          nacos:
            server-addr: 127.0.0.1:8848
            data-id: ${spring.application.name}-flow-rules
            group-id: SENTINEL_GROUP
            data-type: json
            rule-type: flow

6.2 流控规则

Java
/**
 * 注解方式定义Sentinel资源 + 降级
 */
@Service
public class OrderService {

    /**
     * @SentinelResource 定义资源,配置降级和异常处理
     *   - value: 资源名称
     *   - blockHandler: 被Sentinel限流/降级时的处理方法
     *   - fallback: 业务异常时的降级方法
     */
    @SentinelResource(
        value = "createOrder",
        blockHandler = "createOrderBlockHandler",
        fallback = "createOrderFallback"
    )
    public OrderDTO createOrder(CreateOrderRequest request) {
        // 正常业务逻辑
        ProductDTO product = productClient.getProduct(request.getProductId());
        if (product.getStock() < request.getQuantity()) {
            throw new BusinessException("库存不足");
        }
        // ... 创建订单
        return orderDTO;
    }

    /**
     * 被Sentinel限流/熔断时调用
     * 参数列表必须与原方法一致 + 多一个BlockException
     */
    public OrderDTO createOrderBlockHandler(CreateOrderRequest request, BlockException ex) {
        if (ex instanceof FlowException) {
            throw new ApiException(429, "下单太快了,请稍后重试");
        }
        if (ex instanceof DegradeException) {
            throw new ApiException(503, "订单服务暂时不可用,请稍后重试");
        }
        throw new ApiException(429, "请求被限流: " + ex.getClass().getSimpleName());
    }

    /**
     * 业务异常降级
     */
    public OrderDTO createOrderFallback(CreateOrderRequest request, Throwable ex) {
        log.error("创建订单降级处理, request={}", request, ex);
        // 写入消息队列延迟处理
        mqTemplate.asyncSend("ORDER_FALLBACK", request);
        return OrderDTO.builder()
            .status("PENDING")
            .message("订单已提交,稍后处理")
            .build();
    }
}

6.3 热点参数限流

Java
/**
 * 热点参数限流 — 针对频繁访问的特定参数值限流
 * 场景:秒杀活动中,对热门商品ID限流
 */
@SentinelResource(
    value = "getProduct",
    blockHandler = "getProductBlockHandler"
)
public ProductDTO getProduct(Long productId) {
    return productRepository.findById(productId)
        .map(this::convertToDTO)
        .orElseThrow(() -> new NotFoundException("商品不存在: " + productId));
}

/**
 * 编程方式配置热点参数限流规则
 */
@PostConstruct
public void initHotParamRules() {
    ParamFlowRule rule = new ParamFlowRule();
    rule.setResource("getProduct");
    rule.setParamIdx(0);                  // 第0个参数(productId)
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(100);                   // 默认每个参数值QPS上限100

    // 特殊值例外项:热门商品ID限流更严格
    ParamFlowItem item1 = new ParamFlowItem()
        .setObject("1001")                // 热门商品ID
        .setClassType(long.class.getName())
        .setCount(20);                    // 该商品QPS上限20
    ParamFlowItem item2 = new ParamFlowItem()
        .setObject("1002")
        .setClassType(long.class.getName())
        .setCount(20);

    rule.setParamFlowItemList(List.of(item1, item2));
    ParamFlowRuleManager.loadRules(List.of(rule));
}

6.4 熔断降级策略

Java
/**
 * 编程方式配置熔断降级规则
 */
@PostConstruct
public void initDegradeRules() {
    List<DegradeRule> rules = new ArrayList<>();

    // 策略1:慢调用比例 — RT超过200ms的请求比例超过50%时熔断
    DegradeRule slowCallRule = new DegradeRule("createOrder")
        .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
        .setCount(0.5)           // 慢调用比例阈值50%
        .setSlowRatioThreshold(200)  // 慢调用RT阈值200ms
        .setTimeWindow(30)       // 熔断持续30秒
        .setMinRequestAmount(10) // 最小统计请求数
        .setStatIntervalMs(10000); // 统计时长10秒

    // 策略2:异常比例 — 异常比例超过30%时熔断
    DegradeRule errorRatioRule = new DegradeRule("createOrder")
        .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType())
        .setCount(0.3)           // 异常比例30%
        .setTimeWindow(60)       // 熔断持续60秒
        .setMinRequestAmount(10)
        .setStatIntervalMs(10000);

    // 策略3:异常数 — 异常数超过5时熔断
    DegradeRule errorCountRule = new DegradeRule("queryOrder")
        .setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType())
        .setCount(5)             // 异常数5
        .setTimeWindow(60)
        .setMinRequestAmount(5)
        .setStatIntervalMs(60000);

    rules.addAll(List.of(slowCallRule, errorRatioRule, errorCountRule));
    DegradeRuleManager.loadRules(rules);
}

7. 分布式事务

7.1 Seata概述

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的分布式事务解决方案,支持AT、TCC、Saga三种模式。

XML
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
YAML
seata:
  application-id: order-service
  tx-service-group: my_tx_group
  service:
    vgroup-mapping:
      my_tx_group: default
  registry:
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace: ""
      group: SEATA_GROUP

7.2 AT模式(自动补偿,推荐)

AT模式是Seata默认模式,对业务无侵入,自动生成回滚SQL。

Java
/**
 * AT模式 — 下单扣库存扣余额(跨服务事务)
 * 只需在发起方加 @GlobalTransactional
 */
@Service
public class OrderService {

    @Autowired private OrderRepository orderRepository;
    @Autowired private ProductClient productClient;
    @Autowired private AccountClient accountClient;

    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public OrderDTO createOrder(CreateOrderRequest request) {
        // Step 1: 创建订单
        Order order = Order.builder()
            .userId(request.getUserId())
            .productId(request.getProductId())
            .quantity(request.getQuantity())
            .totalAmount(request.getTotalAmount())
            .status(OrderStatus.PENDING)
            .build();
        orderRepository.save(order);

        // Step 2: 扣减库存(远程调用product-service)
        productClient.deductStock(request.getProductId(), request.getQuantity());

        // Step 3: 扣减余额(远程调用account-service)
        accountClient.deductBalance(request.getUserId(), request.getTotalAmount());

        // Step 4: 更新订单状态
        order.setStatus(OrderStatus.CONFIRMED);
        orderRepository.save(order);

        // 任何一步失败,Seata自动回滚所有分支事务
        return convertToDTO(order);
    }
}

AT模式原理:

Text Only
第一阶段(Prepare):
  1. 解析SQL → 查询前镜像(before image)
  2. 执行业务SQL
  3. 查询后镜像(after image)
  4. 生成Undo Log → 写入undo_log表
  5. 注册分支事务 → 获取全局锁
  6. 提交本地事务(业务数据 + undo log一起提交)

第二阶段(Commit/Rollback):
  - 全局提交 → 异步删除undo log
  - 全局回滚 → 根据undo log逆向生成SQL执行回滚

7.3 TCC模式(高性能)

TCC(Try-Confirm-Cancel)模式需要业务代码实现三个阶段,适合高并发场景。

Java
/**
 * TCC模式 — 库存扣减
 * 需要手动实现Try/Confirm/Cancel三个方法
 */
@LocalTCC
public interface StockTccAction {

    /**
     * Try阶段:冻结库存
     */
    @TwoPhaseBusinessAction(
        name = "deductStock",
        commitMethod = "confirm",
        rollbackMethod = "cancel"
    )
    boolean tryDeduct(
        @BusinessActionContextParameter(paramName = "productId") Long productId,
        @BusinessActionContextParameter(paramName = "quantity") int quantity
    );

    /**
     * Confirm阶段:确认扣减(释放冻结量)
     */
    boolean confirm(BusinessActionContext context);

    /**
     * Cancel阶段:取消冻结,恢复库存
     */
    boolean cancel(BusinessActionContext context);
}

@Service
public class StockTccActionImpl implements StockTccAction {

    @Autowired private StockRepository stockRepository;

    @Override
    @Transactional
    public boolean tryDeduct(Long productId, int quantity) {
        // 冻结库存:available - quantity, frozen + quantity
        int updated = stockRepository.freezeStock(productId, quantity);
        if (updated == 0) {
            throw new BusinessException("库存不足");
        }
        return true;
    }

    @Override
    @Transactional
    public boolean confirm(BusinessActionContext context) {
        Long productId = context.getActionContext("productId", Long.class);
        int quantity = context.getActionContext("quantity", Integer.class);
        // 确认扣减:frozen - quantity
        stockRepository.confirmDeduct(productId, quantity);
        return true;
    }

    @Override
    @Transactional
    public boolean cancel(BusinessActionContext context) {
        Long productId = context.getActionContext("productId", Long.class);
        int quantity = context.getActionContext("quantity", Integer.class);
        // 取消冻结:available + quantity, frozen - quantity
        stockRepository.cancelFreeze(productId, quantity);
        return true;
    }
}

7.4 Saga模式(长事务)

Saga模式适合业务流程长、参与服务多的场景,通过编排协同方式实现最终一致性。

Java
/**
 * Saga模式 — 状态机编排方式
 * 通过JSON定义状态机流转
 */
// saga-statemachine.json(Seata Saga状态机定义)
/*
{
  "Name": "createOrderSaga",
  "Comment": "创建订单Saga",
  "StartState": "CreateOrder",
  "States": {
    "CreateOrder": {
      "Type": "ServiceTask",
      "ServiceName": "orderService",
      "ServiceMethod": "createOrder",
      "CompensateState": "CompensateCreateOrder",
      "Next": "DeductStock"
    },
    "DeductStock": {
      "Type": "ServiceTask",
      "ServiceName": "stockService",
      "ServiceMethod": "deductStock",
      "CompensateState": "CompensateDeductStock",
      "Next": "DeductBalance"
    },
    "DeductBalance": {
      "Type": "ServiceTask",
      "ServiceName": "accountService",
      "ServiceMethod": "deductBalance",
      "CompensateState": "CompensateDeductBalance",
      "Next": "Succeed"
    },
    "Succeed": { "Type": "Succeed" },
    "CompensateCreateOrder": { ... },
    "CompensateDeductStock": { ... },
    "CompensateDeductBalance": { ... }
  }
}
*/

// AT vs TCC vs Saga 对比
// | 模式 | 侵入性 | 性能    | 适用场景           |
// |------|--------|---------|-------------------|
// | AT   | 无侵入  | 中等    | 中低并发的CRUD      |
// | TCC  | 高侵入  | 高      | 高并发资金类操作     |
// | Saga | 中侵入  | 中等    | 长事务/多步骤流程    |

8. 链路追踪

8.1 OpenTelemetry集成

OpenTelemetry(OTel)是CNCF的标准化可观测性框架,整合了Tracing、Metrics、Logs。

XML
<!-- Spring Boot 3.x + Micrometer + OTel -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-otel</artifactId>
</dependency>
<dependency>
    <groupId>io.opentelemetry</groupId>
    <artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
YAML
# application.yml
management:
  tracing:
    sampling:
      probability: 1.0          # 采样率100%(生产环境建议0.1~0.5)
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces   # OTel Collector地址

logging:
  pattern:
    level: "%5p [${spring.application.name},%X{traceId},%X{spanId}]"

8.2 自定义Span

Java
@Service
public class PaymentService {

    private final Tracer tracer;

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

    public PaymentResult processPayment(PaymentRequest request) {
        // 创建自定义Span
        Span span = tracer.nextSpan().name("process-payment").start();
        try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
            span.tag("payment.method", request.getMethod());
            span.tag("payment.amount", request.getAmount().toString());
            span.tag("payment.orderId", request.getOrderId());

            // 调用第三方支付
            PaymentResult result = callThirdPartyPayment(request);

            span.tag("payment.status", result.getStatus());
            span.event("payment-completed");
            return result;
        } catch (Exception e) {
            span.error(e);
            throw e;
        } finally {
            span.end();
        }
    }
}

8.3 Jaeger与SkyWalking对比

特性 Jaeger SkyWalking
数据协议 OpenTelemetry / Jaeger原生 OTel / SW私有协议
探针方式 SDK集成 Java Agent(无侵入)
存储后端 Elasticsearch / Cassandra ES / MySQL / BanyanDB
拓扑图 服务拓扑 ✅ 更丰富(实例/端点级别)
告警 基础 ✅ 强大(支持Webhook/钉钉)
性能分析 ✅ 代码级性能剖析
生态 CNCF毕业项目 Apache顶级项目
适用场景 轻量级链路追踪 全方位APM监控
YAML
# SkyWalking Java Agent方式(无侵入)
# JVM启动参数:
# -javaagent:/path/to/skywalking-agent.jar
# -Dskywalking.agent.service_name=order-service
# -Dskywalking.collector.backend_service=127.0.0.1:11800

9. 消息驱动

9.1 Spring Cloud Stream简介

Spring Cloud Stream是Spring Cloud的消息驱动框架,提供统一的编程模型,屏蔽底层MQ差异。

XML
<!-- RocketMQ Binder -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>

9.2 基于函数式编程的消息处理

Java
/**
 * Spring Cloud Stream 函数式消息处理
 * Spring Cloud 2022.x+ 推荐使用函数式方式
 */
@Configuration
public class MessageFunctions {

    /**
     * 消费者:处理订单创建事件
     */
    @Bean
    public Consumer<OrderCreatedEvent> orderCreated() {
        return event -> {
            log.info("收到订单创建事件: orderId={}, userId={}",
                event.getOrderId(), event.getUserId());
            // 发送通知、积分处理等
            notificationService.sendOrderConfirmation(event);
            pointService.addPoints(event.getUserId(), event.getAmount());
        };
    }

    /**
     * 供应者:定时生成报表事件
     */
    @Bean
    public Supplier<ReportEvent> reportGenerator() {
        return () -> {
            ReportEvent event = new ReportEvent();
            event.setTimestamp(Instant.now());
            event.setType("DAILY_SUMMARY");
            return event;
        };
    }

    /**
     * 处理器:消息转换(输入 → 处理 → 输出)
     */
    @Bean
    public Function<PaymentEvent, NotificationEvent> paymentProcessor() {
        return paymentEvent -> {
            log.info("处理支付事件: {}", paymentEvent);
            NotificationEvent notification = new NotificationEvent();
            notification.setUserId(paymentEvent.getUserId());
            notification.setMessage("支付成功,金额: " + paymentEvent.getAmount());
            notification.setChannel("SMS");
            return notification;
        };
    }
}
YAML
# application.yml — Spring Cloud Stream + RocketMQ配置
spring:
  cloud:
    stream:
      # 绑定函数到channel
      function:
        definition: orderCreated;reportGenerator;paymentProcessor
      bindings:
        # 消费者绑定
        orderCreated-in-0:
          destination: order-topic
          group: order-consumer-group
          content-type: application/json
        # 供应者绑定(定时Poller)
        reportGenerator-out-0:
          destination: report-topic
          content-type: application/json
        # 处理器绑定
        paymentProcessor-in-0:
          destination: payment-topic
          group: payment-consumer-group
        paymentProcessor-out-0:
          destination: notification-topic

      rocketmq:
        binder:
          name-server: 127.0.0.1:9876
        bindings:
          orderCreated-in-0:
            consumer:
              tags: "CREATE||UPDATE"      # 消息Tag过滤
              orderly: true               # 顺序消费

9.3 手动发送消息

Java
@Service
public class OrderEventPublisher {

    @Autowired
    private StreamBridge streamBridge;

    /**
     * 手动发送消息到指定Topic
     */
    public void publishOrderCreatedEvent(Order order) {
        OrderCreatedEvent event = OrderCreatedEvent.builder()
            .orderId(order.getId())
            .userId(order.getUserId())
            .amount(order.getTotalAmount())
            .timestamp(Instant.now())
            .build();

        // 发送到指定绑定
        boolean sent = streamBridge.send("orderCreated-out-0", event);
        log.info("订单创建事件发送{}: orderId={}", sent ? "成功" : "失败", order.getId());
    }

    /**
     * 发送延迟消息(RocketMQ特性)
     */
    public void publishDelayedEvent(String orderId) {
        Message<String> message = MessageBuilder.withPayload(orderId)
            .setHeader("DELAY_LEVEL", 16)  // RocketMQ延迟等级(约2小时)
            .build();
        streamBridge.send("order-timeout-out-0", message);
    }
}

9.4 RocketMQ vs Kafka对比

特性 RocketMQ Kafka
延迟消息 ✅ 原生支持(固定等级 / 5.x任意时间) ❌ 需额外方案
事务消息 ✅ 原生支持 ❌ 仅有事务生产者
消费模型 Push + Pull Pull
消息回溯 ✅ 按时间戳 ✅ 按offset
消息过滤 Tag / SQL92 ❌ 需消费端过滤
吞吐量 十万级/秒 百万级/秒
延迟 ms级 ms级
适用场景 电商/金融/可靠消息 大数据/日志/流处理

10. 微服务部署

10.1 Docker Compose编排

YAML
# docker-compose.yml
version: '3.8'

services:
  # ===== 基础设施 =====
  nacos:
    image: nacos/nacos-server:v2.3.0
    ports:
      - "8848:8848"
      - "9848:9848"
    environment:
      - MODE=standalone
      - SPRING_DATASOURCE_PLATFORM=mysql
      - MYSQL_SERVICE_HOST=mysql
      - MYSQL_SERVICE_DB_NAME=nacos_config
      - MYSQL_SERVICE_USER=root
      - MYSQL_SERVICE_PASSWORD=root
    depends_on:
      mysql:
        condition: service_healthy

  mysql:
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: nacos_config
    volumes:
      - mysql-data:/var/lib/mysql
      - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  # ===== 微服务 =====
  gateway:
    build: ./gateway
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - NACOS_ADDR=nacos:8848
    depends_on:
      - nacos

  user-service:
    build: ./user-service
    ports:
      - "8081:8081"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - NACOS_ADDR=nacos:8848
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - nacos
      - mysql
      - redis
    deploy:
      replicas: 2                # 启动2个实例

  order-service:
    build: ./order-service
    ports:
      - "8082:8082"
    environment:
      - SPRING_PROFILES_ACTIVE=docker
      - NACOS_ADDR=nacos:8848
      - DB_HOST=mysql
      - REDIS_HOST=redis
    depends_on:
      - nacos
      - mysql
      - redis
    deploy:
      replicas: 2

volumes:
  mysql-data:

10.2 Dockerfile优化(多阶段构建)

Docker
# ===== 第一阶段:构建 =====
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 使用Maven包装器构建
COPY .mvn .mvn
COPY mvnw .
RUN chmod +x mvnw && ./mvnw clean package -DskipTests

# ===== 第二阶段:运行 =====
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app

# 安全:使用非root用户
RUN addgroup -S app && adduser -S app -G app
USER app

# 拷贝jar
COPY --from=builder /app/target/*.jar app.jar

# JVM调优参数
ENV JAVA_OPTS="-XX:+UseZGC \
  -XX:MaxRAMPercentage=75.0 \
  -XX:+UseStringDeduplication \
  -Djava.security.egd=file:/dev/./urandom"

EXPOSE 8080

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

10.3 Kubernetes部署

YAML
# k8s/user-service-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
  labels:
    app: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0          # 零宕机发布
  template:
    metadata:
      labels:
        app: user-service
        version: v1
    spec:
      containers:
        - name: user-service
          image: registry.example.com/user-service:latest
          ports:
            - containerPort: 8081
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: k8s
            - name: NACOS_ADDR
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: nacos-addr
          resources:
            requests:
              cpu: "250m"
              memory: "512Mi"
            limits:
              cpu: "1000m"
              memory: "1Gi"
          # 就绪探针
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8081
            initialDelaySeconds: 30
            periodSeconds: 10
          # 存活探针
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8081
            initialDelaySeconds: 60
            periodSeconds: 30
          # 优雅停机
          lifecycle:
            preStop:
              exec:
                command: ["sh", "-c", "sleep 10"]
      terminationGracePeriodSeconds: 60

---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - port: 8081
      targetPort: 8081
  type: ClusterIP

10.4 灰度发布(金丝雀发布)

YAML
# 灰度版本Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-canary
  labels:
    app: user-service
    version: v2-canary
spec:
  replicas: 1                  # 少量实例
  selector:
    matchLabels:
      app: user-service
      version: v2-canary
  template:
    metadata:
      labels:
        app: user-service
        version: v2-canary
    spec:
      containers:
        - name: user-service
          image: registry.example.com/user-service:v2-canary
          ports:
            - containerPort: 8081
YAML
# 使用Nginx Ingress实现灰度流量切分
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: user-service-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"          # 10%流量到灰度
    # 也可以按Header分流:
    # nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
    # nginx.ingress.kubernetes.io/canary-by-header-value: "true"
spec:
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api/users
            pathType: Prefix
            backend:
              service:
                name: user-service-canary
                port:
                  number: 8081

11. 面试题

Q1: Nacos作为注册中心,AP模式和CP模式有什么区别?什么场景用哪种?

A:

Text Only
AP模式(临时实例,默认):
- 使用Distro协议(类似Gossip),最终一致性
- 服务实例通过心跳上报,Nacos不主动检查
- 实例宕机后快速移除,注册速度快
- 适合:微服务实例(频繁上下线)

CP模式(持久实例):
- 使用Raft协议,强一致性
- Nacos主动健康检查
- 实例下线后标记为不健康而非删除
- 适合:基础设施服务(DNS、数据库代理 — 不能主动上报心跳的服务)

选择依据:
- 对一致性要求不高、希望高可用 → AP(大多数微服务场景)
- 对数据一致性要求高、服务不能主动上报心跳 → CP

Q2: Spring Cloud Gateway和Nginx的区别?网关限流怎么实现?

A:

Text Only
Spring Cloud Gateway vs Nginx:
┌──────────────┬─────────────────────┬──────────────────────┐
│     特性     │  Spring Cloud GW    │       Nginx          │
├──────────────┼─────────────────────┼──────────────────────┤
│ 定位         │ 业务网关            │ 流量网关(反向代理)   │
│ 服务发现     │ 集成注册中心        │ 需额外配置upstream    │
│ 动态路由     │ 支持(配置中心)    │ 需reload             │
│ 限流         │ Sentinel/Redis      │ limit_req模块        │
│ 鉴权         │ 编程式JWT/OAuth2    │ 基础(Lua脚本扩展)  │
│ 性能         │ 中等(JVM)         │ 高(C语言/事件驱动)  │
│ 协议         │ HTTP/WebSocket      │ HTTP/TCP/UDP         │
└──────────────┴─────────────────────┴──────────────────────┘

生产实践中常用 Nginx(流量网关) → Gateway(业务网关) 二级网关架构。

限流方案:
1. Gateway内置:RequestRateLimiter + Redis(令牌桶算法)
2. Sentinel整合:spring-cloud-alibaba-sentinel-gateway
3. 自定义:GlobalFilter + Redis计数器(滑动窗口)

Q3: Seata AT模式的原理?有什么缺点?

A:

Text Only
原理:
1. TM(事务管理器)开启全局事务,获取XID
2. RM(资源管理器)执行分支事务:
   - 解析SQL → 查询前镜像 → 执行SQL → 查询后镜像
   - 生成undo_log → 注册分支事务 → 获取全局锁
   - 提交本地事务(业务数据 + undo_log)
3. 全局提交 → 异步清理undo_log
4. 全局回滚 → 根据undo_log反向补偿

缺点:
- 全局锁导致并发度降低(写写冲突要排队)
- 不支持SQL联合主键的某些场景
- undo_log增加额外存储成本
- 不适合高并发写场景(锁竞争严重)

优化建议:
- 高并发场景考虑TCC模式
- 减小事务范围,避免长事务
- 适当设置事务超时时间

Q4: 微服务链路追踪的核心原理是什么?TraceId如何跨服务传播?

A:

Text Only
核心原理:
- 分布式追踪基于Google Dapper论文
- 核心概念:Trace(整个请求链路)→ Span(单个操作)
- 每个Span包含:TraceId、SpanId、ParentSpanId、开始/结束时间、标签

TraceId跨服务传播机制:
1. HTTP调用:通过Header传递
   - W3C标准:traceparent: 00-{traceId}-{spanId}-{flags}
   - B3格式:X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId

2. Feign/RestTemplate:自动注入Interceptor,发送请求时添加Header
3. MQ消息:放入消息属性(Message Properties/Headers)
4. 线程池:使用包装的 TraceableExecutorService 传递上下文

Spring Boot 3.x的传播链:
Micrometer Tracing → OTel Bridge → OTel SDK → Exporter → Jaeger/Zipkin/SkyWalking

Q5: Sentinel和Hystrix的核心区别?Sentinel的滑动窗口如何实现?

A:

Text Only
核心区别:
┌──────────────┬───────────────────────┬──────────────────┐
│     特性     │      Sentinel         │     Hystrix      │
├──────────────┼───────────────────────┼──────────────────┤
│ 隔离策略     │ 信号量(默认)        │ 线程池 / 信号量   │
│ 熔断策略     │ 慢调用/异常比/异常数  │ 异常比例          │
│ 实时统计     │ 滑动窗口(LeapArray) │ 滑动窗口(RxJava)│
│ 规则配置     │ 控制台动态推送        │ 需重启生效        │
│ 限流         │ QPS/线程数/热点参数   │ 有限             │
│ 系统保护     │ CPU/Load/RT自适应     │ ❌               │
│ 维护状态     │ 活跃维护             │ 已停更           │
└──────────────┴───────────────────────┴──────────────────┘

Sentinel滑动窗口实现(LeapArray):
- 使用环形数组(ArrayMetric),每个元素是一个时间窗格(WindowWrap)
- 默认1秒分为2个窗格(500ms/个)
- 每个窗格记录:通过数、阻塞数、异常数、RT
- 获取当前时间对应窗格 → 如果窗格已过期则重置
- 统计时遍历所有有效窗格求和
- 相比固定窗口,避免了临界点突发流量问题

Q6: 微服务灰度发布有哪些方案?Spring Cloud如何实现全链路灰度?

A:

Java
/**
 * 全链路灰度发布实现方案:
 *
 * 1. 网关层:根据Header/Cookie/用户ID/IP等打标
 * 2. 服务间传递:通过请求Header传递灰度标记
 * 3. 负载均衡:根据灰度标记选择对应版本的服务实例
 */

// ===== Step 1: 网关灰度标记过滤器 =====
@Component
public class GrayMarkFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");

        // 灰度策略:指定用户 / 百分比 / AB测试组
        boolean isGray = grayRuleService.isGrayUser(userId);

        if (isGray) {
            ServerHttpRequest request = exchange.getRequest().mutate()
                .header("X-Gray", "true")
                .header("X-Version", "v2")
                .build();
            return chain.filter(exchange.mutate().request(request).build());
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() { return 0; }
}

// ===== Step 2: Feign拦截器传递灰度Header =====
@Component
public class GrayFeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        // 从当前请求上下文获取灰度标记并传递
        ServletRequestAttributes attrs = (ServletRequestAttributes)
            RequestContextHolder.getRequestAttributes();
        if (attrs != null) {
            String gray = attrs.getRequest().getHeader("X-Gray");
            if ("true".equals(gray)) {
                template.header("X-Gray", "true");
                template.header("X-Version",
                    attrs.getRequest().getHeader("X-Version"));
            }
        }
    }
}

// ===== Step 3: 自定义负载均衡器(按版本路由) =====
// 根据X-Version Header选择metadata中version匹配的实例

下一章18-Java新特性与GraalVM - Java 22-25新特性、GraalVM Native Image、虚拟线程深入、Panama FFM API