首页/数据/NoSQL 速查/事务外盒:可靠事件发布
本包目录(322 条)
MongoDB99 条Elasticsearch89 条ClickHouse56 条时序与列式28 条
选型与架构50 条

事务外盒:可靠事件发布

业务写入与事件发布要原子:在同一事务里写业务表和 outbox 表,再由中继任务读取 outbox 投递消息,投递成功后标记或删除。这样避免"数据库提交了但消息没发出去"的丢事件问题,代价是引入中继与幂等消费。

NoSQL 速查数据更新于 2026-10-12

外盒流程(MongoDB 事务示意)

外盒流程(MongoDB 事务示意)
// 副本集/分片集群事务内:业务写入 + 外盒事件
const session = db.getMongo().startSession();
session.startTransaction();
try {
  session.getDatabase("app").orders.insertOne(
    { _id: 1001, status: "paid", amount: 128 },
    { session }
  );
  session.getDatabase("app").outbox.insertOne(
    { eventId: UUID(), type: "order.paid", payload: { orderId: 1001 }, status: "pending" },
    { session }
  );
  session.commitTransaction();
} catch (e) {
  session.abortTransaction();
  throw e;
}

// 中继:轮询 pending 并投递,成功后标记 sent(至少一次投递)
中继实现轮询 findOneAndUpdate 抢占,或直接消费 outbox 集合的 change stream
投递语义至少一次;消费端按 eventId 幂等去重
有 CDC 时由 CDC 直接消费变更日志可以省去外盒,但事件格式与过滤条件要在日志层设计
外盒事件建议带唯一 eventId 与业务主键:消费端用唯一索引去重,重复投递不会产生重复副作用。

易错点

  • 先提交业务再发消息:发送失败时事件丢失,下游永远不知道这笔变更
  • 中继与业务共用低优先级连接池且无限重试:投递积压时反过来拖慢业务库

数据来源与参考

  • MongoDB Manual: Transactions
  • microservices.io: Transactional outbox(模式参考)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌