单元1 · 微服务架构与 Spring Cloud 概览
微服务概念、Spring Cloud 组件全景、版本选型、服务拆分原则
- 微服务:将单体拆分为可独立部署的小服务,按业务能力划分边界。
- Spring Cloud:微服务基础设施全家桶:注册、调用、网关、配置、熔断、链路。
- 版本管理:通过 spring-cloud-dependencies BOM 统一管理组件版本。
- 拆分原则:单一职责、数据库隔离、接口契约、独立部署。
实训1.1 微服务架构与 Spring Cloud 组件全景
说明微服务架构的核心思想,并列出 Spring Cloud 主要组件及其职责。
微服务将单体拆分为可独立部署的小服务;Spring Cloud 提供注册中心(Eureka/Nacos)、网关(Gateway)、调用(OpenFeign)、配置(Config)等一整套微服务基础设施。
微服务架构核心思想:
- 按业务能力拆分服务,每个服务独立开发、部署、扩展
- 服务间通过 HTTP/RPC 轻量通信
- 数据存储隔离,每个服务拥有独立数据库
Spring Cloud 核心组件:
- 服务注册发现:Eureka / Nacos
- 服务调用:OpenFeign(声明式 HTTP 客户端)
- 负载均衡:Spring Cloud LoadBalancer
- API 网关:Spring Cloud Gateway
- 配置中心:Spring Cloud Config / Nacos Config
- 熔断降级:Sentinel / Resilience4j
- 分布式事务:Seata
- 链路追踪:Sleuth + Zipkin
实训1.2 版本选型与项目依赖
给出 Spring Boot 3.x + Spring Cloud 2023.x 的依赖管理与父 POM 配置。
Spring Cloud 版本以伦敦地铁站命名;通过 spring-cloud-dependencies BOM 统一管理版本,避免组件版本冲突。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
</parent>
<properties>
<spring-cloud.version>2023.0.1</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
实训1.3 服务拆分原则
以电商系统为例,说明服务拆分的粒度原则与边界划分要点。
按业务域拆分(订单/库存/用户/支付),遵循高内聚低耦合;数据库按服务隔离,禁止跨库直接查询,通过 API 交互。
电商系统服务拆分示例:
- user-service:用户、地址、会员
- order-service:订单、订单项
- product-service:商品、库存
- payment-service:支付、退款
拆分原则:
1. 单一职责:一个服务只做一件事
2. 数据库隔离:服务间禁止访问对方数据库
3. 接口契约:通过 REST/RPC 明确契约
4. 独立部署:每个服务可独立上线与扩缩容
5. 避免过度拆分:小团队优先按业务域合并
单元2 · 服务注册与发现 Eureka
Eureka Server、Eureka Client、服务注册、心跳续约、自我保护
- Eureka Server:注册中心服务端,@EnableEurekaServer 启动。
- Eureka Client:服务提供者/消费者注册与发现,@EnableDiscoveryClient。
- 心跳机制:客户端 30 秒心跳续约,90 秒未续约剔除。
- 自我保护:15 分钟 85% 实例丢失时自我保护,不剔除实例。
实训2.1 搭建 Eureka Server 注册中心
创建 Eureka Server 服务,配置端口与关闭自我保护,启动后访问控制台。
引入 spring-cloud-starter-netflix-eureka-server,启动类加 @EnableEurekaServer;默认端口 8761,控制台展示注册实例。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
# application.yml
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: false
package com.example.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
实训2.2 服务提供者注册到 Eureka
创建 user-service 提供者,注册到 Eureka 并暴露健康检查端点。
引入 eureka-client 依赖并配置 eureka.client.service-url.defaultZone 指向注册中心;spring.application.name 作为服务名。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
# application.yml
spring:
application:
name: user-service
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
实训2.3 Eureka 心跳与自我保护机制
说明 Eureka 心跳续约与自我保护原理,并给出生产环境常用配置。
客户端每 30 秒发送心跳续约;15 分钟内 85% 实例丢失时进入自我保护,不剔除实例;生产建议开启自我保护避免网络抖动误杀。
# 客户端心跳配置
eureka:
instance:
lease-renewal-interval-in-seconds: 30 # 心跳间隔
lease-expiration-duration-in-seconds: 90 # 过期时间
# 服务端自我保护
eureka:
server:
enable-self-preservation: true # 生产开启
renewal-percent-threshold: 0.85 # 续约百分比阈值
# 自我保护触发条件:
# 15 分钟内收到的续约次数 < 期望值的 85% 时进入自我保护
# 期间不注销任何实例,等待网络恢复
单元3 · 服务注册与发现 Nacos
Nacos 安装、服务注册、服务发现、配置管理、命名空间
- Nacos:阿里开源注册中心 + 配置中心,控制台友好。
- 服务发现:spring-cloud-starter-alibaba-nacos-discovery。
- 配置中心:Nacos Config 支持动态刷新,配合 @RefreshScope。
- 三级隔离:命名空间(环境)/ 分组(项目)/ Data ID(配置)。
实训3.1 Spring Cloud Alibaba 集成 Nacos 注册中心
使用 Nacos 作为注册中心,提供者注册服务,消费者发现服务。
引入 spring-cloud-starter-alibaba-nacos-discovery,配置 nacos server-addr;@EnableDiscoveryClient 启用发现能力。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2023.0.1.0</version>
</dependency>
# application.yml
spring:
application:
name: product-service
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
server:
port: 8082
package com.example.productservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
实训3.2 Nacos 配置中心动态刷新
将配置放入 Nacos Config,演示 @RefreshScope 动态刷新配置。
引入 nacos-config 依赖并配置 file-extension;配置变更后调用 refresh 或加 @RefreshScope 自动刷新 Bean 属性。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2023.0.1.0</version>
</dependency>
# bootstrap.yml(或 spring.config.import)
spring:
application:
name: product-service
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yml
# Nacos 配置中心 Data ID: product-service.yml
server:
port: 8082
app:
banner: hello-nacos
package com.example.productservice.config;
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;
@RestController
@RefreshScope
public class ConfigController {
@Value("${app.banner}")
private String banner;
@GetMapping("/banner")
public String banner() {
return banner;
}
}
实训3.3 命名空间与分组隔离
说明 Nacos 命名空间/分组/Data ID 三级隔离机制,并给出配置示例。
命名空间隔离环境(dev/prod),分组隔离同一环境不同项目,Data ID 定位具体配置;客户端通过 namespace/group 选择目标。
# Nacos 三级隔离
# 1. 命名空间 namespace:环境隔离(dev / test / prod)
# 2. 分组 group:同一命名空间下按项目/团队分组(DEFAULT_GROUP)
# 3. Data ID:具体配置文件({spring.application.name}.yml)
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
namespace: dev-namespace-id # 命名空间 ID
group: ORDER_GROUP # 分组
file-extension: yml
discovery:
server-addr: 127.0.0.1:8848
namespace: dev-namespace-id
单元4 · 远程调用 OpenFeign
声明式 HTTP 客户端、@FeignClient、服务间调用、超时与重试
- OpenFeign:声明式 HTTP 客户端,@FeignClient 定义远程接口。
- 启动开关:@EnableFeignClients 开启客户端扫描。
- 超时配置:feign.client.config 设置连接/读取超时。
- 降级:开启 circuitbreaker 后配置 fallback 兜底实现。
实训4.1 OpenFeign 声明式远程调用
在 order-service 中通过 OpenFeign 调用 user-service 的接口获取用户信息。
@FeignClient(name="user-service") 声明客户端接口,方法签名对应提供者 REST 接口;启动类加 @EnableFeignClients。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
package com.example.orderservice.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service")
public interface UserClient {
@GetMapping("/api/users/{id}")
String getUser(@PathVariable("id") Long id);
}
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
实训4.2 Feign 超时与日志配置
配置 OpenFeign 的连接/读取超时,并开启 Feign 请求日志。
feign.client.config.default.connect-timeout 配置超时;logging.level.
# application.yml
feign:
client:
config:
default:
connect-timeout: 5000
read-timeout: 10000
logger-level: full
# 日志级别(FeignClient 接口所在包)
logging:
level:
com.example.orderservice.feign: debug
# Feign 日志级别:
# NONE(默认)、BASIC(URL/时间)、HEADERS(含头)、FULL(全部)
实训4.3 Feign 统一降级 Fallback
为 FeignClient 配置 fallback 降级实现,提供者不可用时返回兜底数据。
开启 feign.circuitbreaker.enabled=true,实现 FeignClient 接口作为 Fallback 类并标注 @Component,@FeignClient 的 fallback 属性指向它。
# application.yml
feign:
circuitbreaker:
enabled: true
package com.example.orderservice.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/api/users/{id}")
String getUser(@PathVariable("id") Long id);
}
@Component
class UserClientFallback implements UserClient {
@Override
public String getUser(Long id) {
return "用户服务暂不可用(降级返回)";
}
}
单元5 · 负载均衡 LoadBalancer
Spring Cloud LoadBalancer、轮询/随机策略、自定义负载均衡
- @LoadBalanced:RestTemplate 按服务名调用并负载均衡。
- LoadBalancer:Spring Cloud 官方负载均衡器,替代 Netflix Ribbon。
- 策略:轮询 / 随机 / 加权 / 最少活跃 / 一致性哈希。
- 选择:无状态服务用轮询,有状态服务用一致性哈希。
实训5.1 LoadBalancer 负载均衡调用
使用 RestTemplate + @LoadBalanced 按服务名调用多个提供者实例,实现负载均衡。
配置类中 @Bean @LoadBalanced RestTemplate;请求 URL 使用服务名 http://user-service/api/...,由 LoadBalancer 选择实例。
package com.example.orderservice.config;
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 {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package com.example.orderservice.controller;
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/user/{id}")
public String getUser(@PathVariable Long id) {
// 服务名由 LoadBalancer 解析为具体实例地址
return restTemplate.getForObject(
"http://user-service/api/users/" + id, String.class);
}
}
实训5.2 自定义负载均衡策略
配置 LoadBalancer 使用随机策略,并了解轮询与随机的区别。
通过 @LoadBalancerClients(defaultConfiguration = ...) 指定策略类;RandomLoadBalancer 随机、RoundRobinLoadBalancer 轮询。
package com.example.orderservice.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@LoadBalancerClients(defaultConfiguration = LbStrategyConfig.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
class LbStrategyConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> supplier,
ObjectProvider<LoadBalancerClientFactory> factory,
String serviceId) {
return new RandomLoadBalancer(
supplier.getIfAvailable(),
factory.getIfAvailable().getLazyProvider(serviceId,
ServiceInstanceListSupplier::getInstance),
serviceId);
}
}
实训5.3 负载均衡策略对比
对比轮询、随机、最少活跃、一致性哈希策略的适用场景。
轮询适合同配置实例;随机简单但波动大;最少活跃把请求给当前连接数最少的实例;一致性哈希保证同一用户固定实例,适合本地缓存场景。
常见负载均衡策略对比:
- 轮询(RoundRobin):依次分配,实现简单,适合实例配置均衡
- 随机(Random):随机选取,压力分布可能不均
- 权重:按实例性能配比权重,性能高者多分配
- 最少活跃(LeastActive):转发给活跃请求数最少的实例
- 一致性哈希(ConsistentHash):相同 key 请求固定实例,
适合会话保持 / 本地缓存场景
选择建议:
- 一般业务:轮询 / 随机即可
- 性能差异大:加权轮询
- 有状态服务:一致性哈希
单元6 · API 网关 Gateway
Spring Cloud Gateway、路由配置、断言、过滤器、跨域
- Gateway:基于 WebFlux 的响应式网关,路由 + 断言 + 过滤器。
- 路由:routes 配置 id/uri/predicates/filters。
- 全局过滤器:GlobalFilter + Ordered 实现统一鉴权、日志。
- 限流:RequestRateLimiter 基于 Redis 令牌桶。
实训6.1 Gateway 路由配置
搭建 Spring Cloud Gateway,配置路由将 /user/** 转发到 user-service。
引入 spring-cloud-starter-gateway,配置 spring.cloud.gateway.routes:id、uri(lb://服务名)、predicates 路径断言。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
# application.yml
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: user-route
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- id: order-route
uri: lb://order-service
predicates:
- Path=/api/order/**
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
实训6.2 Gateway 全局过滤器(鉴权)
编写 GlobalFilter 实现 token 校验:无 token 返回 401,通过则放行。
实现 GlobalFilter 与 Ordered 接口,在 filter 链中检查请求头 Authorization;优先级数字越小越先执行。
package com.example.gateway.filter;
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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
String token = exchange.getRequest()
.getHeaders().getFirst("Authorization");
if (token == null || token.isEmpty()) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100; // 数字越小优先级越高
}
}
实训6.3 Gateway 限流与跨域
配置 RequestRateLimiter 限流过滤器,并开启网关全局 CORS。
RequestRateLimiter 基于 Redis 令牌桶限流,需引入 spring-boot-starter-data-redis-reactive;全局 CORS 用 spring.cloud.gateway.globalcors 配置。
# application.yml
spring:
cloud:
gateway:
default-filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒补充令牌数
redis-rate-limiter.burstCapacity: 20 # 桶容量
redis-rate-limiter.requestedTokens: 1 # 每次请求消耗
globalcors:
cors-configurations:
'[/**]':
allowedOriginPatterns: "*"
allowedMethods: "*"
allowedHeaders: "*"
allowCredentials: true
单元7 · 配置中心 Config / Nacos Config
集中配置、配置刷新、配置加密、灰度配置
- 集中配置:Config Server 从 Git 拉取配置,客户端统一获取。
- fail-fast:配置获取失败快速失败,避免带错误配置启动。
- 动态刷新:/actuator/refresh 或 Bus 广播刷新。
- 安全:jasypt 加密敏感配置,配置中心加认证。
实训7.1 Spring Cloud Config Server 搭建
搭建 Config Server,从 Git 仓库读取配置文件,客户端通过配置中心获取配置。
Config Server 加 @EnableConfigServer,配置 spring.cloud.config.server.git.uri;客户端引入 config-client 并配置 bootstrap 指向服务端。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
# application.yml(config-server)
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/example/config-repo
default-label: main
package com.example.configserver;
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);
}
}
实训7.2 Config Client 获取配置
order-service 作为 Config Client 从配置中心获取数据源与自定义配置。
客户端引入 config-client,bootstrap.yml 配置 spring.cloud.config.uri 指向 Server;启动时按 {name}-{profile}.yml 拉取配置。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
# bootstrap.yml(order-service)
spring:
application:
name: order-service
profiles:
active: dev
cloud:
config:
uri: http://localhost:8888
fail-fast: true
# Git 仓库中的 order-service-dev.yml:
# spring:
# datasource:
# url: jdbc:mysql://localhost:3306/order_dev
# username: root
# password: 123456
实训7.3 配置刷新与安全
通过 /actuator/refresh 实现配置动态刷新,并简述配置中心安全加固。
引入 actuator 暴露 refresh 端点,配置变更后 POST /actuator/refresh;生产可通过 Spring Cloud Bus 广播刷新所有实例;敏感配置用 jasypt 加密。
<!-- 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
# application.yml
management:
endpoints:
web:
exposure:
include: refresh,busrefresh
# 手动刷新单个服务
curl -X POST http://localhost:8082/actuator/refresh
# 广播刷新所有订阅服务(通过 MQ)
curl -X POST http://localhost:8082/actuator/busrefresh
单元8 · 熔断降级 Sentinel
Sentinel 控制台、流控规则、熔断降级、热点参数、网关限流
- Sentinel:阿里流量防卫组件:流控、熔断、降级、热点、系统保护。
- 流控:QPS/并发线程阈值控制入口流量。
- 熔断:异常比例/慢调用达到阈值时短路,防雪崩。
- 热点限流:针对具体参数值(如爆款商品)精准限流。
实训8.1 Spring Cloud Alibaba 集成 Sentinel
在服务中集成 Sentinel,接入控制台并演示最基本的流控规则。
引入 sentinel 依赖并配置 dashboard 地址;Sentinel 控制台可实时查看资源调用与配置流控/降级规则。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2023.0.1.0</version>
</dependency>
# application.yml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台
port: 8719 # 客户端与控制台通信端口
eager: true
# 启动 Sentinel 控制台
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
实训8.2 流控与熔断降级规则
通过 Sentinel 配置 QPS 流控与异常比例熔断,理解两种规则的区别。
流控控制单位时间请求数,超限直接拒绝;熔断在异常比例/慢调用达到阈值时短路,防止服务雪崩;降级返回 fallback 兜底。
# 流控规则
# 资源:GET:/api/order/list
# 阈值类型:QPS,单机阈值 100
# 超出 100 QPS 时,超出请求被拒绝(默认快速失败)
# 熔断规则
# 资源:GET:/api/user/{id}
# 统计时长 1000ms,最小请求数 5
# 异常比例 0.5 → 调用失败比例超 50% 时熔断 10 秒
# 熔断期间调用直接进入 fallback
// 代码中使用 @SentinelResource 定义资源与降级逻辑
@SentinelResource(value = "getOrderList",
fallback = "listFallback")
public List<Order> list() {
return orderRepository.findAll();
}
public List<Order> listFallback(Throwable t) {
return Collections.emptyList();
}
实训8.3 热点参数限流与系统自适应保护
对热点参数(商品 id)配置限流,并理解系统自适应保护的作用。
热点参数限流针对具体参数值限流(如爆款商品单独限流);系统保护基于负载/CPU 自适应调整入口流量,保护整体稳定。
# 热点参数限流(Sentinel 控制台 - 热点规则)
# 资源:getProductDetail
# 参数索引:0(productId)
# 参数例外项:productId=1001 → QPS 阈值 5
# 默认 QPS 阈值:50
// 代码
@SentinelResource("getProductDetail")
public Product getProductDetail(Long productId) {
return productService.getById(productId);
}
# 系统自适应保护(系统规则)
# 入口 QPS 不超过 200
# 系统负载(Load)不超过 5.0
# CPU 使用率不超过 80%
# 平均 RT 不超过 500ms
# 并发线程数不超过 100
单元9 · 分布式事务 Seata
Seata 架构、AT 模式、XA 模式、TCC 模式、Saga 模式
- Seata:分布式事务解决方案,支持 AT/TCC/SAGA/XA。
- 三组件:TC 协调者、TM 事务管理器、RM 资源管理器。
- AT 模式:undo_log 快照 + 两阶段,业务无侵入。
- 选型:通用用 AT,资金高并发用 TCC,长事务用 SAGA。
实训9.1 Seata 架构与 AT 模式原理
说明 Seata 的 TC/TM/RM 三组件与 AT 模式两阶段提交原理。
TC 事务协调者、TM 事务管理器、RM 资源管理器;AT 模式一阶段记录 undo_log 并提交本地事务,二阶段根据全局结果回滚或提交。
Seata 三大组件:
- TC(Transaction Coordinator):全局事务协调者,独立部署
- TM(Transaction Manager):事务发起方,开启/提交/回滚全局事务
- RM(Resource Manager):参与事务的资源,管理分支事务
AT 模式两阶段:
阶段一:RM 执行业务 SQL,同时记录 undo_log 快照,
本地事务提交(无锁等待)
阶段二:全局提交 → 异步删除 undo_log
全局回滚 → 根据 undo_log 反向补偿 SQL
# 启动 TC(seata-server)
seata-server.sh -p 8091 -m file
实训9.2 Seata AT 模式集成
在订单服务中使用 @GlobalTransactional 开启全局事务,扣库存与扣余额保持一致。
引入 seata 依赖并配置 registry;事务发起方方法加 @GlobalTransactional;参与方(库存/账户)只需接入 RM 即可。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2023.0.1.0</version>
</dependency>
# application.yml
seata:
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: ""
group: SEATA_GROUP
application: seata-server
tx-service-group: my_test_tx_group
package com.example.orderservice.service;
import com.example.orderservice.feign.AccountClient;
import com.example.orderservice.feign.StockClient;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final AccountClient accountClient;
private final StockClient stockClient;
public OrderService(AccountClient accountClient,
StockClient stockClient) {
this.accountClient = accountClient;
this.stockClient = stockClient;
}
@GlobalTransactional(name = "create-order-tx",
rollbackFor = Exception.class)
public void createOrder(Long userId, Long productId, int count) {
// 1. 扣库存
stockClient.deduct(productId, count);
// 2. 扣余额
accountClient.deduct(userId, 100 * count);
// 3. 生成订单(本地事务)
// 任一环节异常 → 全局回滚
}
}
实训9.3 事务模式选型
对比 AT / TCC / SAGA / XA 模式的优缺点与适用场景。
AT 无侵入但性能有损耗;TCC 需业务实现 try/confirm/cancel 三接口;SAGA 适合长事务;XA 强一致但性能低。
四种分布式事务模式对比:
| 模式 | 一致性 | 侵入性 | 性能 | 适用场景 |
|------|--------|--------|------|----------|
| XA | 强一致 | 低(依赖数据库) | 低 | 银行转账等强一致 |
| AT | 最终一致 | 低(undo_log 自动) | 中 | 通用业务,最常用 |
| TCC | 最终一致 | 高(三接口) | 高 | 资金类高并发 |
| SAGA | 最终一致 | 中(状态机/编排) | 高 | 长事务、跨系统 |
选择建议:
- 通用微服务业务:AT 模式
- 高并发资金操作:TCC
- 复杂长流程:SAGA
- 强一致要求且低并发:XA
单元10 · 消息驱动 Spring Cloud Stream
Stream 抽象、Binder、发布订阅、消费组、消息分区
- Stream:消息中间件统一抽象,Binder 连接 RabbitMQ/Kafka。
- 通道:@Output 发布、@StreamListener 消费、@EnableBinding。
- 消费组:同组竞争消费,不同组广播消费。
- 分区:partition-key-expression 保证顺序消费。
实训10.1 Stream 集成 RabbitMQ 发布消息
使用 Spring Cloud Stream 的 Source 发布消息到 RabbitMQ 队列。
引入 stream-rabbit 依赖;@Output("output") 声明输出通道,MessageChannel.send 发送消息;binder 自动连接 RabbitMQ。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
# application.yml
spring:
cloud:
stream:
bindings:
output:
destination: order-event # 交换机/主题名
content-type: application/json
package com.example.orderservice.mq;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
@Component
public class OrderPublisher {
private final MessageChannel output;
public OrderPublisher(@Output(Source.OUTPUT) MessageChannel output) {
this.output = output;
}
public void publish(String orderId) {
output.send(MessageBuilder.withPayload(orderId).build());
System.out.println("已发布订单事件:" + orderId);
}
}
实训10.2 Stream 消费消息
使用 @StreamListener 订阅 order-event 队列,处理订单创建事件。
@EnableBinding(Sink.class) 开启输入通道;@StreamListener(Sink.INPUT) 监听消息;消费组保证竞争消费。
package com.example.inventoryservice.mq;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.stereotype.Component;
@Component
@EnableBinding(Sink.class)
public class OrderConsumer {
@StreamListener(Sink.INPUT)
public void onOrder(String orderId) {
System.out.println("库存服务收到订单:" + orderId);
// 扣减库存业务逻辑
}
}
# application.yml
spring:
cloud:
stream:
bindings:
input:
destination: order-event
group: inventory-group # 消费组:同组竞争消费
content-type: text/plain
实训10.3 消息分区与重试
配置消息分区让同一订单消息进入同一分区,并设置消费失败重试。
producer 配置 partition-key-expression 按订单 id 分区;consumer 配置 max-attempts 重试次数与 back-off 间隔。
# application.yml
spring:
cloud:
stream:
bindings:
output:
destination: order-event
producer:
partition-key-expression: payload.id
partition-count: 3
input:
destination: order-event
group: order-group
consumer:
max-attempts: 3 # 最大重试次数
back-off-initial-interval: 1000
back-off-multiplier: 2.0
# 分区后同一订单的消息固定进入同一分区实例,
# 保证顺序消费;重试失败进入 DLQ(死信队列)
单元11 · 链路追踪 Sleuth + Zipkin
Sleuth 链路 ID、Zipkin 采集、依赖注入追踪
- Sleuth:为日志注入 traceId/spanId,串联调用链。
- Zipkin:可视化展示链路调用树、耗时、依赖图。
- 采样率:sleuth.sampler.probability 控制采集比例。
- 异步链路:Spring Async 自动传递 TraceContext。
实训11.1 Sleuth 集成与链路 ID
引入 Spring Cloud Sleuth,观察日志中的 traceId 与 spanId。
引入 sleuth 依赖后日志自动附加 [traceId, spanId];同一请求经过多个服务时 traceId 相同,用于串联调用链。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
# 开启后日志格式
# 2026-08-22 10:00:00.123 [order-service,86f4a2b1c3,86f4a2b1c3,true]
# INFO OrderController - 创建订单
# 字段含义:[服务名, traceId, spanId, 是否采样]
# 调用链示例:
# 网关 → order-service → user-service → database
# 三者日志中 traceId 相同,spanId 不同
实训11.2 Zipkin 可视化链路
集成 Zipkin Server 收集 Sleuth 链路数据,并在 UI 查看调用拓扑。
引入 zipkin 依赖并配置 base-url;Zipkin Server 接收 span 数据,UI 展示调用树、耗时与依赖关系。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
# application.yml
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0 # 采样率,生产建议 0.1
# 启动 Zipkin Server
docker run -d -p 9411:9411 openzipkin/zipkin
# 访问 http://localhost:9411 查看:
# - 按 trace 检索调用链
# - 依赖图展示服务间调用关系
# - 每个 span 的耗时与标签
实训11.3 自定义 Span 与异步链路
在业务代码中手动创建 Span 埋点,并说明异步场景链路传递。
使用 Tracer.nextSpan().start() 手动埋点;异步线程需传递 TraceContext,或用 ExecutorService 装饰器自动注入。
package com.example.orderservice.trace;
import brave.Tracer;
import brave.Span;
import org.springframework.stereotype.Component;
@Component
public class TraceService {
private final Tracer tracer;
public TraceService(Tracer tracer) {
this.tracer = tracer;
}
public void doBusiness(String orderId) {
// 手动创建 Span 埋点
Span span = tracer.nextSpan().name("cache-warm").start();
try (brave.ScopedSpan ignored = tracer.startScopedSpan("save-order")) {
System.out.println("执行业务:" + orderId);
// 业务逻辑...
} finally {
span.finish();
}
}
}
// 异步链路传递:
// - 使用 Spring 的 Async 时 Sleuth 自动注入 TraceContext
// - 自建线程池建议使用 TraceableExecutorService 包装
单元12 · 综合项目:订单微服务调用链
服务拆分、注册发现、Feign 调用、网关路由、链路追踪串联
- 整体架构:网关 + 注册中心 + 多个微服务 + 链路追踪。
- 跨服务调用:Feign 声明式调用 + LoadBalancer 负载均衡。
- 事务一致性:本地事务 + Seata 全局事务。
- 验证手段:日志 traceId + Zipkin 调用树。
实训12.1 项目整体架构搭建
设计订单/用户/库存三个微服务 + 网关 + 注册中心的整体架构,并给出依赖清单。
注册中心统一管理实例;网关统一入口;服务间通过 Feign 调用;链路追踪贯穿全链;每个服务独立数据库。
架构设计:
┌─────────┐ ┌──────────────┐
│ 网关 │───▶│ eureka-server │
│ gateway │ └──────────────┘
└────┬────┘ ▲
│ lb:// │ 注册/发现
┌────▼─────┐ Feign ┌─────┴─────┐
│ order-svc│────────▶│ user-svc │
└────┬─────┘ └───────────┘
│ Feign
┌────▼─────┐
│ stock-svc│
└──────────┘
每个服务依赖:
- spring-cloud-starter-netflix-eureka-client
- spring-cloud-starter-openfeign
- spring-boot-starter-web
- spring-cloud-starter-sleuth + zipkin(链路)
实训12.2 下单接口实现(跨服务调用)
实现下单接口:校验用户 → 扣库存 → 创建订单,通过 Feign 跨服务调用。
OrderService 通过 UserClient 校验用户、StockClient 扣库存;使用 @Transactional 本地事务 + Seata 全局事务保证一致性。
package com.example.orderservice.service;
import com.example.orderservice.entity.Order;
import com.example.orderservice.feign.StockClient;
import com.example.orderservice.feign.UserClient;
import com.example.orderservice.repository.OrderRepository;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final UserClient userClient;
private final StockClient stockClient;
public OrderService(OrderRepository orderRepository,
UserClient userClient,
StockClient stockClient) {
this.orderRepository = orderRepository;
this.userClient = userClient;
this.stockClient = stockClient;
}
public Order create(Long userId, Long productId, int count) {
// 1. 校验用户是否存在
String user = userClient.getUser(userId);
if (user == null || user.contains("不可用")) {
throw new RuntimeException("用户不存在");
}
// 2. 扣减库存
stockClient.deduct(productId, count);
// 3. 创建本地订单
Order order = new Order();
order.setUserId(userId);
order.setProductId(productId);
order.setCount(count);
return orderRepository.save(order);
}
}
实训12.3 网关统一入口与链路验证
配置网关路由聚合下单链路,并通过 Zipkin 验证 traceId 串联。
网关将 /api/order/** 转发 order-service;请求经网关→订单→用户/库存,Zipkin 中呈现完整调用树;无 traceId 说明采样未开启。
# gateway 路由
spring:
cloud:
gateway:
routes:
- id: order-route
uri: lb://order-service
predicates:
- Path=/api/order/**
- id: user-route
uri: lb://user-service
predicates:
- Path=/api/user/**
# 发起下单请求
curl -X POST http://localhost:8080/api/order/create \
-H "Content-Type: application/json" \
-d '{"userId":1,"productId":100,"count":2}'
# 验证链路:
# 1. 各服务日志中 traceId 相同
# 2. Zipkin(http://localhost:9411) 搜索该 traceId
# 可见 网关→订单服务→用户服务/库存服务 调用树