领域事件驱动在微服务中的应用

领域事件驱动在微服务中的应用

核心概念关系

架构关系图:

1
2
3
4
5
6
7
8
9
10
┌─────────────────────────────────────┐
│ 微服务架构 │
│ ┌────────────┐ ┌────────────┐ │
│ │ 订单服务 │ │ 库存服务 │ │
│ └────────────┘ └────────────┘ │
│ │ │ │
│ └───────┬───────┘ │
│ ▼ │
│ 领域事件驱动通信 │
└─────────────────────────────────────┘

优势互补:

  1. 微服务:服务边界清晰、独立部署
  2. 事件驱动:解耦、异步、可扩展

领域事件示例

领域事件定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
public class OrderCreatedEvent {
private String orderId;
private String userId;
private BigDecimal amount;
private Date createTime;

public static OrderCreatedEvent from(Order order) {
OrderCreatedEvent event = new OrderCreatedEvent();
event.setOrderId(order.getId());
event.setUserId(order.getUserId());
event.setAmount(order.getAmount());
event.setCreateTime(new Date());
return event;
}
}

事件发布:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class OrderService {
@Autowired
private EventBus eventBus;

@Transactional
public void createOrder(OrderDTO dto) {
// 1. 创建订单
Order order = orderRepository.save(
Order.create(dto)
);

// 2. 发布领域事件
eventBus.publish(
OrderCreatedEvent.from(order)
);
}
}

事件订阅:

1
2
3
4
5
6
7
8
9
10
@Service
public class InventoryService {
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 扣减库存
inventoryRepository.deduct(
event.getOrderId()
);
}
}

实现方式

技术选型图:

1
2
3
4
┌────────────┐    ┌────────────┐    ┌────────────┐
│ Kafka │ │ RabbitMQ │ │ EventBus │
└────────────┘ └────────────┘ └────────────┘
异步 异步+即时 进程内事件

消息格式示例:

1
2
3
4
5
6
7
8
9
{
"eventId": "xxx",
"eventType": "OrderCreated",
"timestamp": "xxx",
"data": {
"orderId": "xxx",
"userId": "xxx"
}
}

典型应用场景

场景一:订单支付流程

1
2
3
4
┌──────────┐   事件   ┌──────────┐   事件   ┌──────────┐
│订单服务 │───────►│支付服务 │───────►│库存服务 │
└──────────┘ └──────────┘ └──────────┘
OrderCreated PaymentSuccess StockDeducted

场景二:用户注册流程

1
2
3
4
┌──────────┐   事件   ┌──────────┐   事件   ┌──────────┐
│用户服务 │───────►│积分服务 │───────►│消息服务 │
└──────────┘ └──────────┘ └──────────┘
UserRegistered PointsAwarded WelcomeSent

最佳实践

事件发布可靠性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class ReliableEventBus {
@Transactional
public void publish(DomainEvent event) {
// 1. 保存事件到本地消息表
eventRepository.save(event);

// 2. 异步发送消息
kafkaTemplate.send(
"topic",
JSON.toJSON(event)
);
}
}

幂等性处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
public class IdempotentEventHandler {
@EventListener
public void handle(DomainEvent event) {
String key = event.getEventId();
if (processed(key)) {
return;
}

try {
// 处理业务逻辑
processEvent(event);
// 记录已处理
markAsProcessed(key);
} catch (Exception e) {
// 异常处理
}
}
}

注意事项

注意事项列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1. 事件设计原则
- 事件应该是过去时
- 包含必要上下文
- 版本化管理

2. 可靠性保证
- 本地消息表
- 消息幂等性
- 死信队列

3. 性能考虑
- 异步处理
- 批量处理
- 合适的分区

4. 监控告警
- 事件处理延迟
- 失败重试次数
- 积压队列大小