面试知识库
进阶

本地消息表方案#

一句话答案#

业务操作和写消息表在同一本地事务中,后台任务轮询消息表发送 MQ,消费者处理后更新状态,实现最终一致。

核心要点

流程:

  1. 本地事务:业务操作 + INSERT 消息表(同一事务)
  2. 后台定时任务:扫描未发送的消息 → 发 MQ
  3. 消费者处理 → 确认后更新消息状态

优点: 可靠、不依赖额外组件 缺点: 侵入业务表、需要定时轮询

面试回答(2分钟版)

本地消息表是实现分布式最终一致性的经典方案,核心思路是利用本地事务的原子性来保证业务操作和消息记录的一致性。具体流程分三步:第一步在本地数据库事务中同时执行业务操作和插入一条消息记录到消息表,因为在同一个事务中所以要么都成功要么都失败;第二步由后台定时任务扫描消息表中状态为”未发送”的记录,将其投递到MQ;第三步消费者处理完消息后回调确认,更新消息表状态为”已完成”。这个方案的优点是可靠性高,不依赖额外的中间件组件,只要数据库事务能保证就不会丢消息。缺点也很明显:侵入业务表需要额外建消息表,定时轮询有延迟而且增加数据库压力,消息表数据量大了还需要定期归档清理。另外消费端必须做好幂等处理,因为定时任务可能重复发送同一条消息。如果项目中已经用了RocketMQ,建议优先用RocketMQ的事务消息来替代,原理类似但更优雅。

追问与易错

追问方向:

  • “轮询频率怎么设?”→ 根据业务时效性决定,核心链路 510 秒轮询一次,非核心 15 分钟;配合指数退避(多次未成功的消息逐渐降低重试频率)减少 DB 压力
  • “和事务消息比优缺点?”→ 本地消息表不依赖 MQ 特性(任何 MQ 都能用),但侵入业务表且需轮询;事务消息(如 RocketMQ 半消息)更优雅但绑定特定 MQ
  • “消息表数据量大怎么办?”→ 已完成的消息定期归档到历史表或直接删除 + 按时间分区(如按月分表)+ 只保留最近 N 天的活跃数据

易错点:

  • ❌ 消息表是最终一致最佳方案——侵入大推荐事务消息
  • ❌ 忘记处理重复发送