| name | microservice-patterns |
| description | 微服务设计模式与 Spring Cloud Alibaba 实践,涵盖服务拆分、通信、网关、注册发现、配置中心、分布式事务、熔断降级、链路追踪 |
| version | 1.0 |
微服务设计模式
概述
本 Skill 提供微服务架构的核心设计模式和 Spring Cloud Alibaba 的完整实践方案,适用于中大型分布式系统的设计与落地。
适用场景:
- 单体应用拆分为微服务
- 微服务间通信方案选型
- API 网关设计与实现
- 分布式事务、熔断降级、链路追踪落地
服务拆分原则
按限界上下文拆分
# 电商系统拆分示例
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 用户服务 │ │ 商品服务 │ │ 订单服务 │
│ user-svc │ │ product-svc │ │ order-svc │
│ │ │ │ │ │
│ - 注册/登录 │ │ - 商品管理 │ │ - 下单 │
│ - 用户信息 │ │ - SKU 管理 │ │ - 支付 │
│ - 权限管理 │ │ - 库存管理 │ │ - 退款 │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
└────────────────┼────────────────┘
│
┌─────────────────┐
│ 支付服务 │
│ payment-svc │
│ │
│ - 支付渠道对接 │
│ - 对账 │
└─────────────────┘
拆分判断清单
拆分信号(应该拆):
[x] 不同团队负责不同模块
[x] 模块之间变更频率差异大
[x] 模块需要独立扩缩容
[x] 模块的技术栈需求不同
[x] 模块存在清晰的领域边界
不拆信号(保持单体或模块化单体):
[x] 团队人数少于 5 人
[x] 模块间强耦合,频繁互相调用
[x] 没有独立部署的需求
[x] 数据一致性要求极高
服务间通信
同步通信:OpenFeign(REST)
@FeignClient(
name = "product-svc", // 服务名(Nacos 注册名)
fallbackFactory = ProductClientFallbackFactory.class // 降级工厂
)
public interface ProductClient {
@GetMapping("/api/v1/products/{productId}")
Result<ProductDTO> getProduct(@PathVariable("productId") Long productId);
@PostMapping("/api/v1/products/stock/deduct")
Result<Void> deductStock(@RequestBody List<StockDeductRequest> requests);
}
@Component
public class ProductClientFallbackFactory implements FallbackFactory<ProductClient> {
private static final Logger log = LoggerFactory.getLogger(ProductClientFallbackFactory.class);
@Override
public ProductClient create(Throwable cause) {
log.error("商品服务调用失败,触发降级", cause);
return new ProductClient() {
@Override
public Result<ProductDTO> getProduct(Long productId) {
return Result.fail("商品服务暂时不可用,请稍后重试");
}
@Override
public Result<Void> deductStock(List<StockDeductRequest> requests) {
throw new ServiceUnavailableException("库存服务不可用");
}
};
}
}
同步通信:gRPC(高性能场景)
// product.proto — 商品服务接口定义
syntax = "proto3";
package com.example.product;
option java_package = "com.example.product.grpc";
option java_outer_classname = "ProductProto";
// 商品服务
service ProductService {
// 查询商品
rpc GetProduct (GetProductRequest) returns (ProductResponse);
// 批量查询(服务端流)
rpc ListProducts (ListProductsRequest) returns (stream ProductResponse);
}
message GetProductRequest {
int64 product_id = 1;
}
message ProductResponse {
int64 id = 1;
string name = 2;
int64 price_cents = 3; // 价格(分)
int32 stock = 4;
}
@GrpcClient("product-svc")
private ProductServiceGrpc.ProductServiceBlockingStub productStub;
public ProductDTO getProduct(Long productId) {
GetProductRequest request = GetProductRequest.newBuilder()
.setProductId(productId)
.build();
ProductResponse response = productStub.getProduct(request);
return ProductDTO.fromGrpc(response);
}
异步通信:RocketMQ
@Component
public class OrderEventProducer {
private final RocketMQTemplate rocketMQTemplate;
public OrderEventProducer(RocketMQTemplate rocketMQTemplate) {
this.rocketMQTemplate = rocketMQTemplate;
}
public void sendOrderCreatedEvent(OrderCreatedEvent event) {
String topic = "order-topic";
String tag = "order-created";
Message<OrderCreatedEvent> message = MessageBuilder
.withPayload(event)
.setHeader(RocketMQHeaders.KEYS, String.valueOf(event.getOrderId()))
.build();
rocketMQTemplate.syncSend(topic + ":" + tag, message);
}
public void sendOrderTimeoutMessage(Long orderId) {
Message<Long> message = MessageBuilder.withPayload(orderId).build();
rocketMQTemplate.syncSend("order-topic:order-timeout", message, 3000, 16);
}
}
@Component
@RocketMQMessageListener(
topic = "order-topic",
selectorExpression = "order-created",
consumerGroup = "product-consumer-group"
)
public class OrderCreatedConsumer <OrderCreatedEvent> {
StockService stockService;
{
.stockService = stockService;
}
{
stockService.deductStock(event.getItems());
}
}
通信方式选型
场景 推荐方式 原因
──────────────────────────────────────────────────────────
查询类操作 REST/Feign 简单直观,易调试
高频内部调用 gRPC 高性能,强类型
事件通知 消息队列 解耦,削峰
最终一致性 消息队列 可靠投递,重试
实时性要求高 REST/gRPC 同步等待结果
跨语言服务 gRPC IDL + 多语言代码生成
API 网关模式
Spring Cloud Gateway 配置
spring:
cloud:
gateway:
default-filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200
key-resolver: "#{@ipKeyResolver}"
routes:
- id: user-svc
uri: lb://user-svc
predicates:
- Path=/api/user/**
filters:
- name: CircuitBreaker
args:
name: userCircuitBreaker
fallbackUri: forward:/fallback/user
- id: product-svc
uri: lb://product-svc
predicates:
-
全局认证过滤器
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private static final List<String> WHITE_LIST = List.of(
"/api/user/login",
"/api/user/register",
"/api/product/list"
);
private final JwtTokenProvider tokenProvider;
public AuthGlobalFilter(JwtTokenProvider tokenProvider) {
this.tokenProvider = tokenProvider;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
if (WHITE_LIST.stream().anyMatch(path::startsWith)) {
return chain.filter(exchange);
}
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange, "缺少认证令牌");
}
try {
String jwt = token.substring(7);
Claims tokenProvider.parseToken(jwt);
exchange.getRequest().mutate()
.header(, claims.getSubject())
.header(, claims.get(, String.class))
.header(, claims.get(, String.class))
.build();
chain.filter(exchange.mutate().request(mutatedRequest).build());
} (Exception e) {
unauthorized(exchange, );
}
}
{
-;
}
Mono<Void> {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
+ message + ;
exchange.getResponse().bufferFactory().wrap(body.getBytes());
exchange.getResponse().writeWith(Mono.just(buffer));
}
}
服务注册与发现(Nacos)
服务端配置
spring:
application:
name: order-svc
cloud:
nacos:
discovery:
server-addr: ${NACOS_ADDR:127.0.0.1:8848}
namespace: ${NACOS_NAMESPACE:dev}
group: DEFAULT_GROUP
metadata:
version: v1.2.0
env: ${SPRING_PROFILES_ACTIVE:dev}
配置中心(Nacos Config)
spring:
application:
name: order-svc
cloud:
nacos:
config:
server-addr: ${NACOS_ADDR:127.0.0.1:8848}
namespace: ${NACOS_NAMESPACE:dev}
file-extension: yaml
shared-configs:
- data-id: common-db.yaml
group: SHARED_GROUP
refresh: true
- data-id: common-redis.yaml
group: SHARED_GROUP
refresh: true
extension-configs:
- data-id: order-rocketmq.yaml
group: ORDER_GROUP
refresh: true
@ConfigurationProperties(prefix = "order.config")
public class OrderConfig {
private Integer maxRetryTimes = 3;
private Integer timeoutMinutes = 30;
private Boolean enablePromotion = true;
}
分布式事务
Seata Saga 模式(推荐长事务场景)
@Service
public class OrderSagaService {
public OrderDTO createOrder(CreateOrderCommand cmd) {
Order order = Order.create(cmd.getUserId(), cmd.getItems());
orderRepository.save(order);
return OrderDTO.from(order);
}
public void cancelOrder(OrderDTO orderDTO) {
Order order = orderRepository.findById(orderDTO.getId())
.orElseThrow(() -> new OrderNotFoundException(orderDTO.getId()));
order.cancel("Saga 补偿回滚");
orderRepository.save(order);
}
}
@Service
public class StockSagaService {
public void deductStock(List<StockDeductRequest> items) {
items.forEach(item -> {
int stockMapper.deductStock(item.getSkuId(), item.getQuantity());
(affected == ) {
(item.getSkuId());
}
});
}
{
items.forEach(item ->
stockMapper.restoreStock(item.getSkuId(), item.getQuantity())
);
}
}
本地消息表(轻量方案)
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final OutboxRepository outboxRepository;
@Transactional
public Order createOrder(CreateOrderCommand cmd) {
Order order = Order.create(cmd);
orderRepository.save(order);
OutboxMessage message = OutboxMessage.builder()
.topic("order-topic")
.tag("order-created")
.messageKey(String.valueOf(order.getId()))
.payload(JSON.toJSONString(OrderCreatedEvent.from(order)))
.status(OutboxStatus.PENDING)
.build();
outboxRepository.save(message);
return order;
}
}
@Component
public class OutboxPublisher {
private final OutboxRepository outboxRepository;
private final RocketMQTemplate rocketMQTemplate;
@Scheduled(fixedDelay = 1000)
public void publishPendingMessages() {
List<OutboxMessage> messages = outboxRepository
.findByStatusOrderByCreatedAtAsc(OutboxStatus.PENDING, PageRequest.of(0, ));
(OutboxMessage msg : messages) {
{
rocketMQTemplate.syncSend(msg.getTopic() + + msg.getTag(),
MessageBuilder.withPayload(msg.getPayload()).build());
msg.markAsSent();
outboxRepository.save(msg);
} (Exception e) {
msg.incrementRetryCount();
outboxRepository.save(msg);
}
}
}
}
熔断降级(Sentinel)
流控与熔断规则
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
private final OrderAppService orderAppService;
public OrderController(OrderAppService orderAppService) {
this.orderAppService = orderAppService;
}
@GetMapping("/{orderId}")
@SentinelResource(
value = "getOrder",
blockHandler = "getOrderBlock", // 限流/熔断时的处理
fallback = "getOrderFallback" // 业务异常时的降级
)
public Result<OrderVO> getOrder(@PathVariable Long orderId) {
return Result.success(orderAppService.getOrder(orderId));
}
public Result<OrderVO> getOrderBlock(Long orderId, BlockException ex) {
return Result.fail(429, "请求过于频繁,请稍后重试");
}
public Result<OrderVO> getOrderFallback(Long orderId, Throwable ex) {
return Result.fail(503, "订单服务暂时不可用");
}
}
spring:
cloud:
sentinel:
transport:
dashboard: ${SENTINEL_DASHBOARD:localhost:8080}
port: 8719
datasource:
flow:
nacos:
server-addr: ${NACOS_ADDR:localhost:8848}
data-id: ${spring.application.name}-flow-rules
group-id: SENTINEL_GROUP
data-type: json
rule-type: flow
degrade:
nacos:
server-addr: ${NACOS_ADDR:localhost:8848}
data-id: ${spring.application.name}-degrade-rules
group-id: SENTINEL_GROUP
data-type: json
rule-type: degrade
规则定义示例
[
{
"resource": "getOrder",
"limitApp": "default",
"grade": 1,
"count": 100,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
[
{
"resource": "getOrder",
"grade": 0,
"count": 1000,
"slowRatioThreshold": 0.5,
"timeWindow": 30,
链路追踪(SkyWalking)
接入配置
自定义 Span(手动埋点)
@Service
public class PaymentService {
@Trace
@Tags({
@Tag(key = "orderId", value = "arg[0]"),
@Tag(key = "amount", value = "arg[1]")
})
public PaymentResult pay(Long orderId, BigDecimal amount) {
ActiveSpan.tag("payChannel", "alipay");
ActiveSpan.info("开始调用支付渠道");
try {
PaymentResult result = payChannel.execute(orderId, amount);
ActiveSpan.tag("payStatus", result.getStatus().name());
return result;
} catch (Exception e) {
ActiveSpan.error(e);
throw e;
}
}
}
日志关联 TraceId
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [TID:%X{tid}] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="SW_GRPC_LOG" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="SW_GRPC_LOG" />
</root>
</configuration>
微服务技术栈总览
层次 技术选型 说明
─────────────────────────────────────────────────────────────
API 网关 Spring Cloud Gateway 路由、限流、鉴权
服务通信 OpenFeign / gRPC / RocketMQ 同步 + 异步
注册发现 Nacos Discovery 服务注册与健康检查
配置中心 Nacos Config 动态配置热更新
熔断降级 Sentinel 流控、熔断、系统保护
分布式事务 Seata (Saga/TCC) / 本地消息表 根据场景选择
链路追踪 SkyWalking 全链路追踪 + 日志关联
日志收集 ELK (Filebeat + Logstash) 集中式日志管理
监控告警 Prometheus + Grafana 指标采集与可视化
容器编排 Docker + Kubernetes 部署与扩缩容
常见问题速查
| 问题 | 解决方案 |
|---|
| 服务间循环依赖 | 引入事件驱动解耦,或抽取公共服务 |
| Feign 调用超时 | 调整 connectTimeout 和 readTimeout,配合熔断 |
| 分布式 ID 冲突 | 使用雪花算法(Snowflake)或 Leaf |
| 配置变更不生效 | 检查 @RefreshScope 或 @ConfigurationProperties 是否生效 |
| 消息重复消费 | 消费端做幂等处理(唯一键 / 状态机) |
| 链路追踪丢失 | 检查线程池是否传递了 TraceContext |
| 服务雪崩 | 配置 Sentinel 熔断规则 + 降级兜底 |
| 灰度发布 | Nacos metadata + Gateway 路由权重 |