https://debezium.io/blog/2019/02/19/reliable-microservices-data-exchange-with-the-outbox-pattern/

Outbox模式是一种在微服务架构中确保数据更改和消息/事件发布之间可靠性的设计模式。它解决了在更新数据库和发送消息这两个独立操作中可能出现的不一致问题(例如,数据库更新成功但消息发送失败,或者反之)。

Outbox模式的流程通常如下:

  1. 业务操作与事件记录在同一事务中:

    • 当一个服务执行业务操作(例如,创建一个订单、更新一个用户状态),它会在其本地数据库事务中完成两件事:
      1. 更新业务相关的数据库表(例如,Orders表)。
      2. 将一个代表该业务操作结果的事件或消息插入到同一个数据库中的一个专用“outbox”表(例如,OutboxMessages表)。
    • 由于这两个操作在同一个本地数据库事务中,它们要么一起成功提交,要么一起失败回滚。这保证了业务数据的更改和待发送消息的记录是原子性的。
  2. 独立的消息中继/发布者进程:

    • 有一个独立的进程或组件(通常称为消息中继、事件发布者或轮询器)负责监控这个“outbox”表。
    • 这个进程会定期查询outbox表,寻找尚未发送的消息。
  3. 发布消息到消息代理:

    • 一旦消息中继进程从outbox表中获取到新的消息,它会将这些消息发布到外部的消息代理(如 Kafka, RabbitMQ, Azure Service Bus 等)。
  4. 更新/删除Outbox中的消息:

    • 在消息成功发布到消息代理后,消息中继进程会更新outbox表中对应消息的状态(例如,标记为“已发送”)或者直接删除该消息记录。
    • 这一步需要小心处理,以确保消息至少被成功发布一次。如果发布后、更新outbox表前发生故障,消息可能会被重新发布(因此消费者需要具备幂等性)。

Outbox模式与事务消息模式的关系

Outbox模式通常被认为是实现事务性消息传递(Transactional Messaging)或至少是伪事务性消息传递的一种有效方式,尤其是在不使用或无法使用跨数据库和消息代理的分布式事务(如XA事务)的场景下。

  • 目标一致: 两者的核心目标都是确保数据库状态的改变和对应消息的发送能够原子性地完成——要么都成功,要么都失败。
  • 实现方式:
    • 传统的事务消息可能依赖于消息队列本身支持与数据库事务协调的特性(例如某些JMS实现配合XA事务)。
    • Outbox模式通过将“发送消息”这个动作分解为两步(先在本地事务中记录消息,再异步发送)来绕开直接的分布式事务。它利用本地数据库事务的原子性来保证消息意图的持久化,然后通过一个独立的、可靠的机制来确保这个持久化的消息最终被发送出去。

总结:

Outbox模式通过将待发送的消息作为业务数据更改的一部分,原子性地写入服务自身的数据库中,然后通过一个独立的异步进程读取这些消息并将其发布到消息队列,从而实现了高度可靠的消息传递,避免了数据不一致的问题。它是一种非常实用的模式,用于在微服务之间可靠地交换数据和事件。

Debezium本身是一个CDC(Change Data Capture,变更数据捕获)工具,它经常与Outbox模式结合使用,Debezium可以直接监控outbox表的变化,并将这些变化作为事件流式传输到消息代理,从而自动化了上述流程中的第2步和第3步。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐