事件驱动架构:异步解耦的最佳实践

事件驱动架构:异步解耦的最佳实践

事件驱动架构是微服务解耦的核心方案。本文从原理到实战,带你掌握事件驱动设计。


一、什么是事件驱动?

1.1 传统调用 vs 事件驱动

scss 复制代码
传统调用(同步):
OrderService.create() → 调用 InventoryService.deduct() → 调用 PaymentService.pay()
                    ↓ 失败
             全部回滚

事件驱动(异步):
OrderService.create() → 发送 OrderCreatedEvent
  ↓
InventoryService 监听 → 扣减库存 → 发送 StockDeductedEvent
  ↓
PaymentService 监听 → 处理支付

1.2 核心组件

组件 作用
Event 事件对象
Producer 事件生产者
Consumer 事件消费者
Event Bus 事件总线(MQ)

二、事件驱动优势

复制代码
✅ 服务解耦 - 服务间不直接调用
✅ 弹性伸缩 - 消费者独立扩展
✅ 最终一致 - 保证数据最终一致
✅ 流量削峰 - MQ 缓冲流量

三、实战代码

3.1 定义事件

kotlin 复制代码
@Data
public class OrderCreatedEvent {
    private String orderId;
    private String userId;
    private BigDecimal amount;
    private List<OrderItem> items;
    private Long timestamp;
}

3.2 发送事件

scss 复制代码
@Service
public class OrderService {
    
    @Autowired
    private ApplicationEventPublisher publisher;
    
    @Autowired
    private RocketMQTemplate mqTemplate;
    
    public void createOrder(OrderRequest request) {
        // 1. 创建订单
        Order order = orderMapper.insert(request);
        
        // 2. 发送事件
        OrderCreatedEvent event = OrderCreatedEvent.builder()
            .orderId(order.getId())
            .userId(order.getUserId())
            .amount(order.getAmount())
            .items(order.getItems())
            .timestamp(System.currentTimeMillis())
            .build();
        
        mqTemplate.asyncSend("order-created", event, new SendCallback() {
            @Override
            public void onSuccess(SendResult result) {
                log.info("事件发送成功");
            }
            @Override
            public void onException(Throwable e) {
                log.error("事件发送失败", e);
            }
        });
    }
}

3.3 消费事件

less 复制代码
@Service
@RocketMQMessageListener(
    topic = "order-created",
    consumerGroup = "inventory-consumer"
)
public class InventoryConsumer implements RocketMQListener<OrderCreatedEvent> {
    
    @Autowired
    private InventoryService inventoryService;
    
    @Override
    public void onMessage(OrderCreatedEvent event) {
        try {
            // 幂等性检查
            if (processed(event.getOrderId())) {
                return;
            }
            
            // 扣减库存
            for (OrderItem item : event.getItems()) {
                inventoryService.deduct(item.getProductId(), item.getQuantity());
            }
            
            // 发送下一个事件
            eventPublisher.publishEvent(new StockDeductedEvent(event));
            
        } catch (Exception e) {
            log.error("库存扣减失败", e);
            // 进入死信队列
        }
    }
}

四、常见问题

4.1 幂等性

typescript 复制代码
// 使用 Redis 去重
public boolean isDuplicate(String eventId) {
    return !redisTemplate.opsForValue()
        .setIfAbsent("event:" + eventId, "1", 24, TimeUnit.HOURS);
}

4.2 顺序性

arduino 复制代码
// 使用消息队列的分区
// 相同 orderId 的消息发到同一个分区
rocketMQTemplate.syncSendOrderly(
    "order-topic",
    message,
    orderId  // 分区键
);

4.3 事务性

typescript 复制代码
// 事务消息
@Transactional
public void createOrder(OrderRequest request) {
    Order order = orderMapper.insert(request);
    
    // 事务消息:本地事务成功才发送
    TransactionMQProducer producer = new TransactionMQProducer();
    producer.sendMessageInTransaction(
        new Message("order-topic", JSON.toJSONBytes(order)),
        new LocalTransactionExecuter() {
            @Override
            public LocalTransactionState executeLocalTransactionBranch(Message msg, Object arg) {
                // 执行业务逻辑
                return LocalTransactionState.COMMIT_MESSAGE;
            }
        }
    );
}

五、架构模式

5.1 事件溯源(Event Sourcing)

csharp 复制代码
// 不存储状态,只存储事件
@Entity
public class OrderAggregate {
    private String orderId;
    private List<OrderEvent> events = new ArrayList<>();
    
    public void apply(OrderCreatedEvent event) {
        events.add(event);
        // 重放所有事件得到当前状态
    }
}

5.2 CQRS

less 复制代码
// 读写分离
@Service
public class OrderQueryService {
    // 读:从 Elasticsearch/Redis 查询
}

@Service
public class OrderCommandService {
    // 写:生成事件,写入 Event Store
}

六、技术选型

MQ 特点 适用场景
Kafka 高吞吐、持久化 日志、大数据
RabbitMQ 路由灵活 企业集成
RocketMQ 事务消息 电商金融
Pulsar 云原生 多租户

相关推荐
JavaGuide1 小时前
NVIDIA 又开源了!这次给 AI Agent 加上权限管控
前端·后端
excel1 小时前
prisma 如何处理数据库竞态
前端·数据库·后端
IT_陈寒3 小时前
Java线程池这破玩意,差点让我周末加班排查到凌晨
前端·人工智能·后端
弈栈录4 小时前
Java AI 应用的异步化与高并发设计
java·后端·架构
凤山老林4 小时前
Spring Boot 集成 iText 7 实现动态 PDF 生成与电子签章:合同、报表场景实战
spring boot·后端·pdf·itext7·电子签章
孙启超4 小时前
【AI开发之Rust】第 19 课:UniFFI 导出核心能力
开发语言·后端·rust
ServBay5 小时前
基于Jev的浏览器Agent插件狂揽 21k star,3分钟教你解放双手
后端·aigc·ai编程
Json____5 小时前
家居装修 AI 智能咨询助手:让装修咨询从“大海捞针“变成“一问即答“
java·后端·vue3·it学习·wwwoop.com
Apifox6 小时前
Apifox 9 月更新|CLI 能力升级、GitLab 私有化部署接入与产品体验优化
前端·后端·测试
鱼弦6 小时前
Agent智能体 vs 传统运维:职业天花板的3倍差距?
后端