Spring Cloud 微服务知识点详解
本文基于 Spring Cloud 2023.x / Spring Boot 3.2.x / Spring Cloud Alibaba 2023.x,系统讲解微服务核心组件原理与实战,配合完整可运行 Java 代码示例。
目录
- 微服务架构概述
- [Spring Cloud 生态全景](#Spring Cloud 生态全景)
- 服务注册与发现(Nacos/Eureka/Consul)
- [负载均衡(Spring Cloud LoadBalancer)](#负载均衡(Spring Cloud LoadBalancer))
- 服务间调用(OpenFeign/RestTemplate/WebClient)
- 熔断与降级(Sentinel/Resilience4j)
- [API 网关(Spring Cloud Gateway)](#API 网关(Spring Cloud Gateway))
- [配置中心(Nacos Config/Spring Cloud Config)](#配置中心(Nacos Config/Spring Cloud Config))
- [链路追踪(Micrometer Tracing/Zipkin)](#链路追踪(Micrometer Tracing/Zipkin))
- [消息驱动(Spring Cloud Stream)](#消息驱动(Spring Cloud Stream))
- 分布式事务(Seata)
- [Spring Cloud Alibaba](#Spring Cloud Alibaba)
- [服务网格(Service Mesh)简介](#服务网格(Service Mesh)简介)
- 微服务最佳实践
一、微服务架构概述
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 查询),有
spanId和parentId,表达调用树关系。 -
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/SupplierBean 定义消息处理逻辑。
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 |
掌握这些组件的原理与协作关系,并结合最佳实践(容错、幂等、可观测性),才能构建高可用、易维护的微服务系统。
