当前位置: 首页 > news >正文

腾讯二面:如何保证MQ消息不丢失?重复消费如何保证幂等,本地消息表配合MQ实现最终一致性?

收银台系统如何实现跨库分布式事务?——基于本地消息表与 MQ 的最终一致性实践

在金融级系统中,数据一致性是生命线。
我们在收银台系统中,通过「本地消息表 + 消息队列」的组合,在不依赖 Seata 等中间件的前提下,实现了跨基本库与交易库的可靠分布式事务,并完成了服务间的异步解耦。


一、业务背景:收银台的跨库挑战

我们的收银台系统涉及两类核心数据:

数据库职责示例
基本库(Basic DB)存储用户身份、会员等级、可用权益(如优惠券、积分、免费额度)user_benefits
交易库(Transaction DB)存储订单、支付记录、账单等交易流水orders, payments

典型场景:用户使用“会员免费额度”下单

  1. 用户发起支付请求
  2. 系统从 基本库 扣减其免费额度(权益)
  3. 同时在 交易库 创建订单和支付记录
  4. 返回支付结果

这两个操作跨两个物理数据库,无法用一个本地事务保证原子性。如果只扣了权益但没建订单,或只建了订单但没扣权益,都会导致资损或用户体验问题。


二、为什么不用 Seata?

虽然 Seata 提供了 AT、TCC 等模式,但在我们评估后,发现:

  • 引入 Seata 会增加运维复杂度(需部署 TC、维护 undo_log 等)
  • 对数据库有侵入(如需要全局锁、undo 表)
  • 在高并发支付场景下,性能损耗不可忽视
  • 团队更倾向于 轻量、可控、可审计 的方案

因此,我们选择了 更经典、更透明的「本地消息表 + MQ」方案


三、解决方案:本地消息表 + MQ 实现最终一致性

核心思路

将跨库操作拆解为:本地事务 + 异步消息通知,通过“先写消息再发 MQ”的方式,确保关键动作不丢失。

具体流程(以“扣权益 → 创建订单”为例)

步骤 1:在基本库中执行本地事务
-- 基本库(Basic DB)
BEGIN;-- 1. 扣减用户权益(如免费额度)
UPDATE user_benefits SET free_quota = free_quota - 100 
WHERE user_id = 123 AND free_quota >= 100;-- 2. 插入本地消息表(同一事务!)
INSERT INTO local_outbox (msg_id, business_type, payload, status, create_time
) VALUES ('msg_20251116_001','CREATE_ORDER','{"userId":123, "amount":100, "benefitUsed":true}','pending',NOW()
);COMMIT;

✅ 此时:权益已扣 + 消息已落库,两者强一致。

步骤 2:异步任务投递消息到 MQ
  • 后台补偿服务定时扫描 local_outboxstatus = 'pending' 的记录
  • 调用 RocketMQ/Kafka 发送消息
  • 发送成功 → 更新状态为 sent
  • 失败 → 重试(带退避策略)
步骤 3:交易库消费消息,创建订单
  • 订单服务监听 MQ
  • 收到消息后,在 交易库 中创建订单和支付记录
  • 必须做幂等处理(如通过 msg_id 或业务唯一键去重)

四、本地消息表带来的三大价值

✅ 1. 保证跨库操作的最终一致性

  • 即使服务宕机、MQ 不可用,消息也不会丢失
  • 重启后自动补偿,确保“权益扣了,订单一定建”

✅ 2. 实现真正的异步解耦

  • 基本库服务(权益中心)不直接调用订单服务
  • 两者通过 MQ 通信,独立演进、独立部署
  • 订单服务故障时,消息可堆积,不影响权益扣减主流程

✅ 3. 规避分布式事务中间件的复杂性

  • 无需引入 Seata、XA、2PC 等重型方案
  • 所有逻辑透明可控,便于审计、排查、回滚

五、关键设计细节

项目实践建议
消息表命名建议叫 local_outbox(业界通用术语)
消息内容冗余关键业务字段,避免后续查表失败
幂等性消费端用 msg_id 做唯一索引,防止重复创建订单
重试机制最多重试 N 次(如 5 次),失败后进入死信队列人工处理
监控告警监控 pending 消息积压量、发送成功率
清理策略成功消息保留 7~30 天后归档,避免表过大

六、为什么不直接发 MQ?

你可能会问:为什么不在扣权益后直接 syncSend 消息?

答案是:无法保证原子性

  • 如果先发 MQ 再 commit:MQ 成功但 commit 失败 → 白送权益
  • 如果先 commit 再发 MQ:commit 成功但发 MQ 前宕机 → 权益扣了但订单没建

只有把“发消息”变成“事务的一部分”(即先写本地消息表),才能从根本上解决这个问题。

技术没有银弹,但有最适合业务的方案。
我们的实践证明:简单、透明、可靠的架构,往往走得更远。

腾讯二面:如何保证MQ消息不丢失?重复消费如何保证幂等?-腾讯云开发者社区-腾讯云

http://www.dtcms.com/a/617694.html

相关文章:

  • RocketMQ生产者多种API实战使用
  • UI设计公司审美积累|办公类软件界面设计巧思,效率与视觉的双重升级
  • 力扣1513——仅含 1 的子串数
  • Kali Linux 中对某(靶机)监控设备进行漏洞验证的完整流程(卧室监控学习)
  • 将LabelMe工具目标检测标注生成的json文件转换成COCO json格式
  • 什么是求解器?
  • 课后作业-2025年11月16号作业
  • C#面试题及详细答案120道(116-120)-- 综合应用
  • 【报错解决】宝塔nginx404
  • 生信数据分析流程自动化:Snakemake实战全攻略
  • 网站建设什么专业重庆品牌餐饮加盟网站建设
  • 数据库 搭建 网站泉州手机网站建设价格
  • 小米电脑管家 V5.2.0.207 新版分享,镜像链接更稳定,AI自动亮度上线,分布式文件开放使用
  • 深入理解 Vue 3 中的计算属性与侦听器:联系、区别及与函数的对比
  • 2.FPGA板卡通过电脑映射连接上网
  • RTCP包之SR和RR
  • 40 token
  • 如何在 Celestia 区块链上构建验证者节点的详细手册
  • Linux权限知识点
  • MySQL: 数据库读写分离与负载均衡的实现方式及深度分析
  • 红帽企业Linux:企业级开源操作系统领航者
  • 怎么做网站开发建一个电商平台多少钱
  • 人工智能技术- 语音语言- 05 GPT-4o 自然人机对话
  • HarmonyOS实用指南:harmonyos + 华为
  • 什么是Spring Boot 应用开发?
  • uniapp实现android/IOS消息推送
  • 汽车网站开发流程html5 网站开发软件
  • HarmonyOS:harmonyos从入门到落地
  • OpenCV(二十九):高通滤波-索贝尔算子
  • 幽冥大陆(二十一)go语言智慧农业电子秤读取——东方仙盟炼气期