问个分布式事务的问题

340 天前
 7911364440

业务流程大概是这样,从 RocketMQ 消费消息,将收到的数据转发给多个数据源(可能是 MySQL 、Oracle 、Kafka 等)。
问题是如何保证一条消息最终成功发送给所有客户端?假设写 MySQL 成功了,发送 Kafka 时失败了,要怎么重发

目前想到的方案:

  1. 将发送失败的消息保存到本地数据库,同时记录目标客户端,再通过定时任务重发。
  2. 跟 1 类似,将失败的消息发送到消息队列中的某个特定的 topic ,客户端消费这个 topic 实现重发。
1783 次点击
所在节点    程序员
23 条回复
lhcnic
340 天前
RocketMQ 不是自带消费重试的吗?
sujin190
340 天前
或许可以更粗暴点,从 RocketMQ 收到消息通过新的交换机再次发送 RocketMQ 各个不同的数据源队列去,然后各数据源各自消费者,反正不成功消息不会从队列消息,自动就有重试
wangpugod2003
340 天前
你这个需求,是保证整个流程,做到消息的 exactly once 处理.
首先需要确认发出去了,每个模块收到了回 ack, 没有就 retry 该模块; 这样保证 > 1; 注意 retry 多次后如果没收到,再到定时任务中设置一段时间后重发,如果再没收到可以放到 dead message queue 中人工处理;
然后每个对端都要 idempotent ,确保收到的消息(maybe > 1)但是只处理 1 次。一般是需要一个 transaction ID 。
xhinliang
340 天前
第一种方法,用事务消息

第二种,用 MySQL 记录下所有的客户端的发送状态
1. 在准备发送前,写入 MySQL ,初始化所有客户端的写入状态为 INIT
2. 给每一个客户端发送,发送成功则修改 MySQL 对应客户端的写入状态为 SUCC ,失败则修改为 FAILED
3. 异步进程扫描所有状态为 INIT 或者 FAILED 的记录,重发
xuanbg
340 天前
消息的消费者如果消费不成功,就把接收到的消息发送到延时队列。延时队列绑定正常的队列,这样过期时间到了就好自动转移到正常的队列里面,就能再次消费。如此循环不息,总有成功的时候。
7911364440
340 天前
@lhcnic 问题是需要保证所有客户端都成功接收。如果写 MySQL 成功了,发送 Kafka 时失败了,只需要给 Kafka 重发,不能给所有客户端都重发一遍,会有重复数据。
7911364440
340 天前
@sujin190 逻辑上应该是可行的,实现起来也很简单,但是会导致一条消息会出现在多个 topic 中,客户端越多冗余的数据就越多,太占用空间了,这个业务每天上千万的数据量,还有图片之类的数据,每条消息都很大。
wu00
340 天前
如果你不能改变数据来源(RocketMQ)
建议在[RocketMQ] 到 [写入多个数据源] 之间加一层 MQ 或者数据库,让整个业务变成多个独立的事务单元
比如:接收到 RocketMQ 的消息,写入到 MQ ,有几个数据源写几条消息,再加一个消费端专门消费 MQ 中的消息分别写入各自的数据源。
ConfusedBiscuit
340 天前
分布式事务,自己想方案容易绕晕,可以找一些成熟的方案,比如 TCC 模型就比较简单易懂。收到 RocketMQ 消息后,自己按照 TCC 模型封装每个下游( MySQL 、Oracle 之类的比较简单,Kafka 之类的可能需要考虑用一些新特性)
dqzcwxb
340 天前
你这个思路没有问题,但是注意的是要保证重发时的幂等
Dream95
340 天前
@7911364440 RocketMQ 本来就会存在重复消费问题,需要在消费者端去重的
Dream95
340 天前
@7911364440 可以用不同的消费组实现
notwaste
340 天前
做好做好监控,然后人工肉偿
silypie
340 天前
一般都是自动重试,多次失败后人工处理吧
silypie
340 天前
保证最终一致就行
coderxy
340 天前
要想实现分布式事务,最基本的一个点就是下游要自己保证幂等, 否则无从谈起。
jorneyr
340 天前
这个是数据一致性吧,不算分布式事务,直接多次轮询进行补偿把没完成的给完成。
如果是分布式事务,A 成功,B 失败,需要把 A 的操作给回滚。
LeeSeoung
340 天前
有个极端情况要考虑哈,比如你发给某个消费端超时了,你认为是失败的,但是实际消费端是成功的,这个时候你做重试,要保证消费端的幂等。
lvxiaomao
340 天前
感觉是没有问题的, 只要消费短幂等就好
xyjincan
340 天前
kafka 好呀,不同类型客户消费,使用不同分组就行,共享一个消息队列

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/942575

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX