写数据库mq消息事务一致性解决方案

原文连接:https://cloud.tencent.com/developer/article/1478827数据库

若是咱们要在服务化拆分中使用消息队列,那么咱们须要解决哪些问题呢?首先去哪儿网提供了旅游产品在线预订服务,那么就涉及电商交易,在电商交易中咱们认为数据的一致性是很是关键的要素。那么咱们的 MQ 必须提供一致性保证。网络

MQ 提供一致性保证又分为两个方面。发消息时咱们如何确保业务操做和发消息是一致的,也就是不能出现业务操做成功消息未发出或者消息发出了可是业务并无成功的状况。举例来讲,支付服务使用消息通知出票服务,那么不能出现支付成功,可是消息没有发出,这会引发用户投诉;可是也不能出现支付未成功,可是消息发出最后出票了,这会致使公司损失。总结一下就是发消息和业务须要有事务保证。一致性的另外一端是消费者,好比消费者临时出错或网络故障,咱们如何确保消息最终被处理了。那么咱们经过消费 ACK 和重试来达到最终一致性。运维

3、利用数据库事务解决一致性问题server

提到一致性,你们确定就想到事务,而一提到事务,确定就想到关系型数据库,那么咱们是否是能够借助关系型 DB 里久经考验的事务来实现这个一致性呢。咱们以 MySQL 为例,对于 MySQL 中同一个实例里面的 db,若是共享相同的 Connection 的话是能够在同一个事务里的。如下图为例,咱们有一个 MySQL 实例监听在 3306 端口上,而后该实例上有 A,B 两个 DB,那么下面的伪代码是能够跑在同一个事务里的队列

有了这层保证,咱们就能够透明的实现业务操做和消息发送在同一个事务里了,首先咱们在公司全部 MySQL 实例里初始化出一个 message db,这个能够放到自动化流程中(听说在去哪儿由运维团队完成),对应用透明。而后咱们只要将发消息与业务操做放到同一个 DB 事务里便可。事务

咱们来看一个实际的场景,在支付场景中,支付成功后咱们须要插入一条支付流水,而且发送一条支付完成的消息通知其余系统。那么这里插入支付流水和发送消息就须要是一致的,任何一步没有成功最后都会致使问题。那么就有下面的代码get

上面的代码能够用下面的伪代码解释消息队列

实际上在 producer.sendMessage 执行的时候,消息并无经过网络发送出去,而仅仅是往业务 DB 同一个实例上的消息库插入一条记录,而后注册事务的回调,在这个事务真正提交后消息才从网络发送出去,这个时候若是发送到 server 成功的话消息会被当即删除掉。而若是消息发送失败则消息就留在消息库里,这个时候咱们会有一个补偿任务会将这些消息从消息库里捞出而后从新发送,直到发送成功。整个流程就以下图所示产品

一、begin tx 开启本地事务自动化

二、do work 执行业务操做

三、insert message 向同实例消息库插入消息

四、end tx 事务提交

五、send message 网络向 server 发送消息

六、reponse server 回应消息

七、delete message 若是 server 回复成功则删除消息

八、scan messages 补偿任务扫描未发送消息

九、send message 补偿任务补偿消息

十、delete messages 补偿任务删除补偿成功的消息