资讯动态

本地消息表(本地事务表)

发布时间:2026/9/27 3:17:45 来源:尧图企业网站定制
目录一、核心思想二、本地消息表字段设计常用三、完整执行流程阶段 1业务方本地事务原子阶段 2定时任务轮询投递阶段 3消费端处理四、优缺点✅ 优点❌ 缺点五、常见坑 优化点六、和其他方案对比七、适用场景八、变种事务状态表 / 可靠消息表核心用途实现分布式事务最终一致性方案最经典的「可靠消息最终一致性」方案也叫事务消息的落地思路不依赖 MQ 事务消息能力也能做。一、核心思想把业务操作和消息记录放在同一个本地数据库事务里。在同一个事务中执行业务 SQL 插入一条本地消息记录状态待发送事务提交成功 → 消息已经落库事务回滚 → 消息记录也一起回滚不会产生脏消息单独起一个消息投递任务定时任务轮询本地消息表把状态 待发送的消息投递到 MQMQ 投递成功更新本地消息状态为已发送投递失败则重试直到成功消费端消费成功后也可以回调更新状态消费失败则消费端自行重试 / 人工兜底一句话用本地数据库事务保证【业务执行】和【消息落库】原子性再通过定时任务保证消息一定能发出去。二、本地消息表字段设计常用sqlCREATE TABLE local_message ( id BIGINT PRIMARY KEY AUTO_INCREMENT, msg_id VARCHAR(64) NOT NULL COMMENT 消息唯一id幂等key, topic VARCHAR(64) NOT NULL COMMENT MQ主题, msg_content TEXT NOT NULL COMMENT 消息体JSON, status TINYINT NOT NULL COMMENT 消息状态0待发送1已发送2发送失败3已消费, retry_count INT DEFAULT 0 COMMENT 重试次数, next_retry_time DATETIME COMMENT 下一次重试时间退避, create_time DATETIME NOT NULL, update_time DATETIME NOT NULL, UNIQUE KEY uk_msg_id(msg_id) );状态枚举0待发送业务事务提交成功消息入库还没投 MQ1已发送成功推送到 MQ2发送失败投递 MQ 失败等待定时任务重试3已消费消费方成功处理三、完整执行流程阶段 1业务方本地事务原子开启本地事务 1. 更新业务数据例订单创建、扣库存 2. insert 本地消息记录 status0 提交事务✅ 要么业务和消息同时入库要么一起回滚不会出现业务成功消息没记录的情况。阶段 2定时任务轮询投递定时任务比如每 5s查询status in (0,2) AND next_retry_time now() AND retry_count max拿到消息先锁行悲观锁 / SELECT ... FOR UPDATE防止多实例重复投递发送消息到 MQ✅ MQ 返回成功 → update status1更新 update_time❌ MQ 异常 / 超时 → retry_count1设置退避时间status2超过最大重试次数 → 标记为死信人工后台处理⚠️ 这里会有消息重复投递网络抖动MQ 收到消息但是 ACK 丢了本地任务重试所以消费端必须做幂等阶段 3消费端处理消费者收到消息先根据msg_id做幂等判断消费记录表执行业务逻辑业务处理成功ACK失败不 ACKMQ 重发可选消费成功后回调生产者接口更新本地消息表 status3已消费四、优缺点✅ 优点实现简单不需要依赖特殊的分布式事务组件TCC、Seata AT不依赖 MQ 的事务消息RocketMQ 才有事务消息Kafka/RabbitMQ 没有本地消息表通用可靠性高消息持久化到数据库宕机重启后定时任务继续重试可控重试次数、退避策略、死信人工处理都可以自己控制❌ 缺点对业务库有侵入多一张消息表业务表和消息表在同一个库增加数据库压力定时任务轮询有延迟不适合强实时场景最终一致性不是强一致高并发场景轮询扫描消息表会有数据库压力需要加索引、分库分表、分页限制重复消息必然存在消费端必须幂等五、常见坑 优化点重复投递问题定时任务投递成功但是更新本地消息表超时任务再次重试投递。 解决消费端幂等唯一 msg_id。定时任务多实例重复捞取消息多台服务同时跑定时任务读到同一条消息并发投递。 解决数据库行锁select ... for update或者分布式锁Redisson。轮询扫全表性能差不要select * from local_message where status0status 建立联合索引(status, next_retry_time)分页查询限制每次捞取条数。重试风暴失败消息不要固定间隔重试使用指数退避10s → 30s → 1min → 5min。消息表数据膨胀历史已消费消息可以定时归档迁移到历史表避免表越来越大。六、和其他方案对比本地消息表 VS MQ 事务消息RocketMQ本地消息表通用性强所有 MQ 都能用业务库多一张表代码量稍多RocketMQ 事务消息不用建本地消息表只能 RocketMQ 使用理解成本高半消息机制本地消息表 VS TCC本地消息表最终一致性适合异步通知场景订单创建通知积分、通知库存TCC强补偿型适合短事务、资金类代码侵入更大本地消息表 VS Seata ATSeata AT全局事务追求接近强一致依赖 Seata 组件有锁、性能损耗七、适用场景适合异步通知、最终一致性场景订单创建成功后通知积分服务发放积分支付成功后通知订单、物流、会员系统 不适合转账、扣余额这类强一致性业务。八、变种事务状态表 / 可靠消息表还有一种消息状态表方案和本地消息表思路几乎一样只是把消息体放到 MQ本地只存消息状态减少数据库存储压力。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑