单体架构 vs 微服务的取舍
微服务不是银弹,也不是"更先进"的必然选择。在决定采用微服务架构前,需要认真评估成本与收益。
单体架构的优势
- 开发简单,本地调试方便
- 事务边界清晰(单一 DB)
- 部署运维成本低
- 性能好(无网络调用开销)
- 适合小团队(< 5 人)
微服务的适用场景
- 不同模块需要独立扩缩容
- 大型团队需要并行开发
- 技术异构(不同语言/框架)
- 部分模块需要高可用隔离
- 业务复杂度已超过单体边界
核心概念名词解释
服务注册与发现
服务启动时向注册中心(Eureka/Nacos/Consul)上报自己的地址和元数据;调用方从注册中心查询目标服务的实例列表,通过负载均衡选择一个实例发起调用。无需硬编码 IP:Port。
OpenFeign
Spring Cloud 提供的声明式 HTTP 客户端。通过定义接口 + 注解,无需手写 RestTemplate 代码,自动集成负载均衡、熔断、日志等功能。调用远程服务像调用本地方法一样简单。
LoadBalancer(负载均衡)
Spring Cloud LoadBalancer(替代旧版 Ribbon)在客户端侧实现负载均衡,从注册中心获取实例列表,按轮询(Round-Robin)或随机(Random)策略选择实例。
熔断器(Circuit Breaker)
防止级联故障的保护机制。当某个服务持续失败时,熔断器"断开"——后续请求直接返回降级响应,不再等待超时。一段时间后进入半开状态,尝试少量请求,若成功则"闭合"恢复正常。
Resilience4j
轻量级容错库,Spring Cloud 推荐的 Hystrix 替代品。提供熔断器(CircuitBreaker)、限流(RateLimiter)、重试(Retry)、舱壁隔离(Bulkhead)、超时(TimeLimiter)等模式。
服务网格(Service Mesh)
将服务间通信的横切关注点(负载均衡、熔断、认证、链路追踪)从应用代码中剥离,下沉到基础设施层(Sidecar Proxy,如 Envoy)。Istio 是最流行的服务网格实现。
Spring Cloud 核心组件全景
┌─────────────────────────────────────────────────────────────────┐
│ Spring Cloud 生态全景 │
└─────────────────────────────────────────────────────────────────┘
客户端请求
│
▼
┌──────────────────────────────────────┐
│ Spring Cloud Gateway(API 网关) │ ← 路由、鉴权、限流、日志
│ 路由规则:/user-service/** → user-svc │
│ 路由规则:/order-service/** → ord-svc │
└──────────────────────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ User │ │ Order Service │
│ Service │ │ │
│ │ │ @FeignClient │ ─── 调用 → Product Service
│ │ │ Resilience4j │ ─── 熔断降级
└──────────────┘ └──────────────────┘
│ │
└─────────┬───────┘
│ 所有服务注册/发现
▼
┌─────────────────────┐
│ Nacos / Eureka │ ← 服务注册中心 + 配置中心
│ 注册表: │
│ user-service → [...] │
│ order-service → [...]│
└─────────────────────┘
分布式链路追踪:Micrometer + Zipkin / Jaeger
配置管理:Spring Cloud Config / Nacos Config
OpenFeign 声明式客户端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
// 主启动类开启 Feign
@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication { ... }
// 定义 Feign 客户端接口
@FeignClient(
name = "product-service", // 注册中心的服务名
fallback = ProductClientFallback.class // 降级实现
)
public interface ProductClient {
@GetMapping("/products/{id}")
ProductDTO getProduct(@PathVariable Long id);
@PostMapping("/products/{id}/decrease-stock")
void decreaseStock(@PathVariable Long id,
@RequestBody StockDecreaseRequest req);
}
// 降级实现(熔断后返回默认数据)
@Component
public class ProductClientFallback implements ProductClient {
@Override
public ProductDTO getProduct(Long id) {
// 降级:返回默认商品信息
return ProductDTO.builder().id(id).name("商品暂时不可用").build();
}
@Override
public void decreaseStock(Long id, StockDecreaseRequest req) {
throw new ServiceUnavailableException("库存服务暂时不可用");
}
}
Resilience4j 熔断器配置
resilience4j:
circuitbreaker:
instances:
product-service: # 针对 product-service 的熔断配置
sliding-window-size: 10 # 滑动窗口大小(10次请求)
failure-rate-threshold: 50 # 失败率 ≥ 50% 时熔断
wait-duration-in-open-state: 10s # 断开状态等待 10s
permitted-number-of-calls-in-half-open-state: 3
automatic-transition-from-open-to-half-open-enabled: true
retry:
instances:
product-service:
max-attempts: 3
wait-duration: 500ms
retry-exceptions:
- java.net.ConnectException # 只重试连接异常
Spring Cloud Gateway 路由配置
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service # lb:// 使用负载均衡
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: RequestRateLimiter # 限流过滤器
args:
redis-rate-limiter.replenishRate: 100 # 每秒 100 个令牌
redis-rate-limiter.burstCapacity: 200
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- name: CircuitBreaker
args:
name: order-service-cb
fallbackUri: forward:/fallback/orders
Tip
微服务不是银弹。团队少于 5 人、业务处于探索期、服务间边界不清晰时,强行拆分微服务往往弊大于利。建议先用良好的模块化单体(Modular Monolith)积累业务理解,当某个模块真的需要独立扩缩容时再拆分。
Warning
微服务中的分布式事务是最大挑战。避免使用两阶段提交(2PC),优先考虑业务可接受的最终一致性方案:Saga 模式(将分布式事务拆解为一系列本地事务)或者借助 Seata AT 模式自动管理。