开办网站需要什么资质,网站备案负责人幕布照,桂林网站制作找志合网络公司,做网站知乎Seata 与消息队列#xff08;如 RocketMQ#xff09;结合实现最终一致性#xff0c;通常采用 “本地事务消息表 异步通知” 的混合模式#xff0c;核心思路是通过 Seata 保障核心业务事务的原子性#xff0c;利用消息队列实现跨服务异步解耦。以下是完整实现方案#xf…Seata 与消息队列如 RocketMQ结合实现最终一致性通常采用 “本地事务消息表 异步通知” 的混合模式核心思路是通过 Seata 保障核心业务事务的原子性利用消息队列实现跨服务异步解耦。以下是完整实现方案 架构设计原理 #mermaid-svg-ZB3Eh0jybFbDdiMb {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .error-icon{fill:#552222;}#mermaid-svg-ZB3Eh0jybFbDdiMb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZB3Eh0jybFbDdiMb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .marker.cross{stroke:#333333;}#mermaid-svg-ZB3Eh0jybFbDdiMb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .cluster-label text{fill:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .cluster-label span{color:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .label text,#mermaid-svg-ZB3Eh0jybFbDdiMb span{fill:#333;color:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .node rect,#mermaid-svg-ZB3Eh0jybFbDdiMb .node circle,#mermaid-svg-ZB3Eh0jybFbDdiMb .node ellipse,#mermaid-svg-ZB3Eh0jybFbDdiMb .node polygon,#mermaid-svg-ZB3Eh0jybFbDdiMb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .node .label{text-align:center;}#mermaid-svg-ZB3Eh0jybFbDdiMb .node.clickable{cursor:pointer;}#mermaid-svg-ZB3Eh0jybFbDdiMb .arrowheadPath{fill:#333333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZB3Eh0jybFbDdiMb .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZB3Eh0jybFbDdiMb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZB3Eh0jybFbDdiMb .cluster text{fill:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb .cluster span{color:#333;}#mermaid-svg-ZB3Eh0jybFbDdiMb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZB3Eh0jybFbDdiMb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1. 开启Seata全局事务 2. 执行业务SQL 3. 写本地消息表 4. 提交Seata事务 5. 轮询消息表 6. 发送事务消息 7. 消费消息 8. 执行业务 协调 协调 服务A Seata TC 业务DB 消息中继 RocketMQ 服务B 下游DB 七步实现最终一致性
步骤1业务服务A发起方
开启Seata全局事务 GlobalTransactional 注解开启分布式事务执行业务SQL 更新本地业务数据库如订单状态写入本地消息表 在同一个本地事务中写入消息记录保证原子性INSERT INTO local_message (id, biz_id, mq_topic, mq_body, status)
VALUES (msg001, order123, INVENTORY_TOPIC, {productId:100,delta:-1}, UNSENT);步骤2Seata事务提交
Seata提交全局事务 TC 协调所有分支事务包括本地消息表写入若全部成功全局事务提交任一失败全局事务回滚自动清理本地消息表
步骤3消息中继服务
轮询本地消息表 定时扫描 statusUNSENT 的消息发送RocketMQ事务消息TransactionSendResult result producer.sendMessageInTransaction(new Message(INVENTORY_TOPIC, message.getBody()), localMessage.getId() // 事务ID
);更新消息状态 消息发送成功后更新状态为 SENT
步骤4下游服务B
监听并消费消息RocketMQMessageListener(topic INVENTORY_TOPIC, consumerGroup inventory-group)
public void deductInventory(Message msg) {// 解析消息体InventoryDTO dto JSON.parse(msg.getBody());// 执行库存扣减可嵌套Seata事务inventoryService.deduct(dto.getProductId(), dto.getDelta());
}保证消费幂等性 通过唯一业务ID如订单号避免重复处理 关键技术保障
1. 消息可靠性机制
环节保障措施消息生产不丢失Seata事务保证消息写入本地表与业务操作原子性消息投递不丢失RocketMQ事务消息半消息机制 中继服务重试3次以上消息消费不丢失RocketMQ ACK机制 消费者重试队列防消息堆积动态调整消费者并发数 死信队列监控
2. 最终一致性兜底方案 消息状态校对 独立定时任务扫描本地消息表 SELECT * FROM local_message
WHERE status UNSENT AND created_time NOW() - INTERVAL 5 MINUTE;对未发送消息重新投递对已发送未ACK消息人工介入 业务对账补偿 日终对账服务检查业务状态一致性 # 伪代码示例
for order in unpaid_orders:if inventory_reserved(order.product_id): trigger_compensation(order) # 触发库存释放Seata与RocketMQ的深度集成优化
方案1Seata-RocketMQ Connector
// 自动将Seata事务与RocketMQ事务绑定
GlobalTransactional
public void createOrder(Order order) {orderDAO.insert(order);// 自动发送事务消息无需手动写消息表rocketMQTemplate.sendInTransaction(INVENTORY_TOPIC, MessageBuilder.withPayload(order).build());
}实现原理 通过 Seata RMHandler 拦截器在分支事务注册时同步注册 RocketMQ 事务
方案2基于CDC的消息发布 #mermaid-svg-ZpbQ379nQNHgZPrN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .error-icon{fill:#552222;}#mermaid-svg-ZpbQ379nQNHgZPrN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZpbQ379nQNHgZPrN .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-ZpbQ379nQNHgZPrN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZpbQ379nQNHgZPrN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZpbQ379nQNHgZPrN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZpbQ379nQNHgZPrN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZpbQ379nQNHgZPrN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZpbQ379nQNHgZPrN .marker.cross{stroke:#333333;}#mermaid-svg-ZpbQ379nQNHgZPrN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZpbQ379nQNHgZPrN .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .cluster-label text{fill:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .cluster-label span{color:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .label text,#mermaid-svg-ZpbQ379nQNHgZPrN span{fill:#333;color:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .node rect,#mermaid-svg-ZpbQ379nQNHgZPrN .node circle,#mermaid-svg-ZpbQ379nQNHgZPrN .node ellipse,#mermaid-svg-ZpbQ379nQNHgZPrN .node polygon,#mermaid-svg-ZpbQ379nQNHgZPrN .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZpbQ379nQNHgZPrN .node .label{text-align:center;}#mermaid-svg-ZpbQ379nQNHgZPrN .node.clickable{cursor:pointer;}#mermaid-svg-ZpbQ379nQNHgZPrN .arrowheadPath{fill:#333333;}#mermaid-svg-ZpbQ379nQNHgZPrN .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZpbQ379nQNHgZPrN .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZpbQ379nQNHgZPrN .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-ZpbQ379nQNHgZPrN .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-ZpbQ379nQNHgZPrN .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZpbQ379nQNHgZPrN .cluster text{fill:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN .cluster span{color:#333;}#mermaid-svg-ZpbQ379nQNHgZPrN div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZpbQ379nQNHgZPrN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 解析binlog 业务DB Debezium CDC Kafka Stream Processing RocketMQ 优势业务零侵入数据库变更自动触发消息挑战需要解决消息顺序性和重复消费 对比传统方案
方案一致性保障性能复杂度适用场景Seata本地消息表⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️通用场景纯MQ事务消息⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️简单跨服务事务TCC模式⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️强一致性金融场景Saga模式⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️⭐️长事务高并发 生产实践建议 消息表设计优化 CREATE TABLE local_message (id BIGINT PRIMARY KEY,biz_id VARCHAR(64) NOT NULL, -- 业务唯一IDmq_topic VARCHAR(64) NOT NULL,mq_body JSON NOT NULL,status ENUM(UNSENT,SENT,FAILED) NOT NULL,created_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,sent_time TIMESTAMP,INDEX idx_status (status), -- 状态索引加速扫描INDEX idx_created (created_time) -- 时间索引用于清理
);中继服务关键配置 # RocketMQ生产者
rocketmq:producer:group: seata-relay-groupretryTimesWhenSendFailed: 5sendMsgTimeout: 3000# 消息扫描策略
relay:scan-interval: 5000 # 5秒扫描一次batch-size: 200 # 每次最大处理量max-retry: 10 # 最大重试次数监控指标 关键指标 seata_transaction_success_rate mq_message_delay_seconds compensation_trigger_count报警规则 消息积压 1000条 最终一致性延迟 1小时 典型应用场景
电商下单流程
订单服务创建订单Seata事务本地消息表记录库存扣减消息库存服务异步扣减库存若库存不足触发补偿流程生成退款单
银行转账场景 #mermaid-svg-23C5MMfyb6oqPSqn {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-23C5MMfyb6oqPSqn .error-icon{fill:#552222;}#mermaid-svg-23C5MMfyb6oqPSqn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-23C5MMfyb6oqPSqn .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-23C5MMfyb6oqPSqn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-23C5MMfyb6oqPSqn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-23C5MMfyb6oqPSqn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-23C5MMfyb6oqPSqn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-23C5MMfyb6oqPSqn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-23C5MMfyb6oqPSqn .marker.cross{stroke:#333333;}#mermaid-svg-23C5MMfyb6oqPSqn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-23C5MMfyb6oqPSqn .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-23C5MMfyb6oqPSqn text.actortspan{fill:black;stroke:none;}#mermaid-svg-23C5MMfyb6oqPSqn .actor-line{stroke:grey;}#mermaid-svg-23C5MMfyb6oqPSqn .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-23C5MMfyb6oqPSqn .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-23C5MMfyb6oqPSqn #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-23C5MMfyb6oqPSqn .sequenceNumber{fill:white;}#mermaid-svg-23C5MMfyb6oqPSqn #sequencenumber{fill:#333;}#mermaid-svg-23C5MMfyb6oqPSqn #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-23C5MMfyb6oqPSqn .messageText{fill:#333;stroke:#333;}#mermaid-svg-23C5MMfyb6oqPSqn .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-23C5MMfyb6oqPSqn .labelText,#mermaid-svg-23C5MMfyb6oqPSqn .labelTexttspan{fill:black;stroke:none;}#mermaid-svg-23C5MMfyb6oqPSqn .loopText,#mermaid-svg-23C5MMfyb6oqPSqn .loopTexttspan{fill:black;stroke:none;}#mermaid-svg-23C5MMfyb6oqPSqn .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-23C5MMfyb6oqPSqn .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-23C5MMfyb6oqPSqn .noteText,#mermaid-svg-23C5MMfyb6oqPSqn .noteTexttspan{fill:black;stroke:none;}#mermaid-svg-23C5MMfyb6oqPSqn .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-23C5MMfyb6oqPSqn .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-23C5MMfyb6oqPSqn .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-23C5MMfyb6oqPSqn .actorPopupMenu{position:absolute;}#mermaid-svg-23C5MMfyb6oqPSqn .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-23C5MMfyb6oqPSqn .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-23C5MMfyb6oqPSqn .actor-man circle,#mermaid-svg-23C5MMfyb6oqPSqn line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-23C5MMfyb6oqPSqn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 账户A服务 RocketMQ 账户B服务 Seata 开启Seata事务 扣减A账户余额 写入转账消息表 提交全局事务 中继服务投递消息 消费转账消息 增加B账户余额 消费ACK 账户A服务 RocketMQ 账户B服务 Seata 总结技术选择建议
强一致性场景 直接使用 Seata AT/TCC 模式 跨服务调用最终一致性场景 Seata本地消息表RocketMQ 是黄金组合 ✅ 利用 Seata 保障核心事务原子性✅ 通过本地消息表实现可靠事件✅ 依赖 RocketMQ 保证消息可靠投递✅ 消费者幂等设计解决重复消费
这种架构平衡了数据一致性与系统性能是分布式系统中应用最广泛的最终一致性实现范式。