写 DB 和发送下游消息要放到一个事务里面吗

2020-10-19 11:13:35 +08:00
 rihkddd

业务中经常有这种需求,比如新增一个订单,需要发 mq 消息到下游系统。看到把这两个操作放到一个事务的写法,那么这么做能达到这么写的目的吗(写数据 /发消息符合事务的四个特性)?

个人总觉得这么写是有问题的,但是说不出根本的问题点是什么。大家这种需求一般是怎么实现的?

3243 次点击
所在节点    程序员
19 条回复
13823133214
2020-10-19 11:20:42 +08:00
确保生产者发送成功
zczy
2020-10-19 11:22:35 +08:00
两套系统单纯加个事务还是有问题的吧,万一 mq 成功了,网络有问题回滚了数据库
coyove
2020-10-19 11:26:13 +08:00
你的担心其实来自于数据库 tx commit 失败的情况,如果不是分布式事务的话这种概率太小了,靠对账和 ack 就可以
zpfhbyx
2020-10-19 11:27:22 +08:00
mq 不要混到事务里, 生产者失败的话重试或者落 db,事务回滚不依赖 mq...
hun2008hun
2020-10-19 11:27:28 +08:00
发消息是网络请求,结果是(成功、失败、超时),超时的时候本地事务要 commit 还是 rollback 呢?
zczy
2020-10-19 11:31:07 +08:00
幂等 + ack 基本上能保证了吧

还有什么本地消息表之类的,用数据库事务保证
rihkddd
2020-10-19 12:22:42 +08:00
@zczy
@zpfhbyx
@coyove
@hun2008hun
感谢各位的回复,从你们的回复看,放到一个事务的做法应该是不对的。
rihkddd
2020-10-19 12:23:55 +08:00
@zczy 是的,去哪儿的 qmq 就是这么个思路实现事务消息特性的。
GGGG430
2020-10-19 12:48:13 +08:00
你说的事务是本地事务表吗, 如果是那就是分布式事务的操作, 用本地事务表来保证发送消息成功.
是不是还有一个定时任务监视本地事务表呢, 正常流程是发送消息成功后删除本地事务表中关联的数据行, 没法送成功则会有后续的定时任务来重发
jorneyr
2020-10-19 13:24:37 +08:00
1. 落库,标记为待处理
2. MQ 发送成功
3. MQ 的回调处理落库的数据,标记为处理完成
sambawy
2020-10-19 13:51:31 +08:00
不要混在一起,消息发送的成功与否不要影响数据状态的落库,否则会因为一两个消息发送的异常导致一批数据回滚,到时候客户那边就被消息轰炸了
CoderGeek
2020-10-19 14:06:32 +08:00
常用手段是本地事务消息, 一般是集中业务库中会有个 localmessage 随着业务比如订单的落库一起保存这 message,然后使用 TransactionSynchronizationAdapter 巴拉巴拉的啥的 保证消息与业务 DB 操作在一个事务,然后应用的线程异步发送 mq 或者半同步这一类的

问题是性能受影响,下游需要幂等 多余的服务开销 但是做肯定是做的到的
CoderGeek
2020-10-19 14:08:56 +08:00
常用的应该是我说的第一类
```java
begin transaction

biz_code();

insertMessage();

callback();

end;

callback 方案可以使用 spring 事务机制进行回调

function callback(){//异步 or 同步

var rtn = sendMqMessage();

If(rtn){

delMessage();

}

}

对于 callback 发送失败问题,会有定时任务去消息表里面获取未成功发送的消息进行重试,在一定次数还为成功的消息,报警人工干预。
```
nutting
2020-10-19 15:07:59 +08:00
发消息可能比较耗时吧,不能放到事务里,我觉得是这个角度考虑?
js8510
2020-10-20 09:06:49 +08:00
同 @jorneyr 的 1,2,3
zhangdashuan
2020-10-20 09:21:53 +08:00
用事务消息应该可以避过这个问题
RedBeanIce
2020-10-20 09:33:38 +08:00
看到支付的流程图

写库,发送消息,调用支付,要放到一个事务里面。

否则你写了库也是脏数据,没有人回去消费他
rihkddd
2020-10-20 12:33:17 +08:00
@GGGG430 不是的,事务就是 mysql db 的事务,数据是写的业务数据。你说的实现看起来没问题。要讨论的是仅把写数据和发消息两个操作放到一个 db 事务中的做法,能否达到预期效果。
rihkddd
2020-10-20 12:35:35 +08:00
@jorneyr 很标准的流程,就是可能需要在业务表里面维护一下消息的状态~

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

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

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

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

© 2021 V2EX