大家好,我是狼王,一个爱踢球的程序员想必大家都不陌生,比如经常提到的ACID,不过对于后续的分布式事务内容,先说ACID,再介绍什么是分布式事务,最后重点介绍基于可靠消息的分布式事务解决方案。什么是交易?严格意义上的事务应该是原子的、一致的、隔离的、持久的,简称ACID。原子性可以理解为一个事务内的所有操作要么执行要么不执行。一致性可以理解为满足完整性约束的数据,即不会有中间状态数据。比如你钱包有100,我钱包有100,你给我50元。这时候你钱包里的钱应该是50,我钱包里的钱应该是150,不会出现我的钱加了你的钱没扣的中间状态。隔离是指多个事务并发执行时不会相互干扰,即一个事务内部的数据与其他事务隔离。持久性是指在一次交易完成后,数据永久保存,后续其他操作或失败不会影响交易结果。通俗的理解,事务就是为了让一些更新操作要么成功,要么失败。什么是分布式事务?顾名思义,分布式事务就是在分布式系统中实现事务。它实际上是由多个本地事务组成的。一个大操作由不同的小操作组成,这些小操作分布在不同的服务器上。分布式事务需要确保这些小操作要么全部成功,要么全部失败。本质上,分布式事务是为了保证不同数据库的数据一致性。常见的分布式事务解决方案如下:2PC、3PC、TCC、本地消息表、可靠消息最终一致性、besteffortnotification等,今天我们将重点介绍可靠消息最终一致性的解决方案什么是Reliable消息最终一致性方案Thereliable消息最终一致性方案是指事务发起者在执行完本地事务后向消息中间件发送消息时,事务参与者(消息消费者)必须能够接收到消息并成功处理事务。该方案强调只要向交易参与者发送消息,最终的交易就必须是一致的。这种方法有什么问题?本方案是通过消息中间件实现的。事务发起者(消息生产者)向消息中间件发送消息,事务参与者从消息中间件接收消息。由于网络通信的不确定性,导致分布式事务问题,如下图:1.本地事务和消息的原子性问题,如上图虚线框所示,有以下几种情况:1)如果本地事务提交失败,消息将不会被发送。2)本地事务成功,消息发送失败,本地事务回滚。3)本地消息成功,消息超时,本地事务回滚,最后消息失败。4)本地消息成功,消息超时,本地事务回滚,消息终于成功。综上所述,有第四种情况,导致本地交易与消息参与者的交易不一致。2、交易参与者接收消息的可靠性。消息中间件和事务参与者必须确保消息能够被成功消费。3、消息的重复消费注意事务参与方接口的幂等性。消息参与者可能已成功使用它。由于网络问题,消息中间件认为消息没有被消费,发起重试后出现问题。方案一、本地消息表本地消息表的关键是有一个本地记录表,用于存储消息日志,需要启动定时任务不断扫描消息日志记录,以保证消息能够发送出去。具体过程如下:上图中的过程:1)事务发起者执行本地事务成功,并在本地消息表中记录消息日志。2)启动定时任务,循环扫描本地消息表。3)当定时任务扫描到消息时,将消息发送给消息中间件。4)消息中间件收到消息,成功返回消息并向事务发起方发送成功通知。5)事务发起方收到消息并发送成功后删除日志消息。6)交易参与者订??阅和消费消息。7)交易参与者处理本地交易。8)本地事务处理成功,向消息中间件发送成功ack。注意事项:交易参与者保证接口的幂等性。2、RocketMq事务消息方案ApacheRocketMQ4.3以后的版本正式支持事务消息,为分布式事务的实现提供了方便的支持。RocketMQ4.3之后实现了完整的事务消息。其实就是对本地消息表的封装,将本地消息表移到MQ内部,解决Producer端发送消息和本地事务执行的原子性问题。实现过程:1)事务发起者发送Half事务消息2)RocketMq回复Half发送成功3)事务发起者执行本地事务4)事务发起者执行本地事务成功,发送commit给RocketMq,mq将消息传递给交易参与者;事务发起方执行本地事务失败,向RocketMq发送回滚,mq删除消息。5)当RocketMq在一定时间内没有收到交易发起方的确认信息时,会对交易发起方进行交易审核。6)交易发起方查询本地交易状态。7)事务发起者根据查询到的事务状态向RocketMq发送commit/rollback。8)当RocketMq发起commit没有收到或者一定时间内没有收到成功的ack时,会发起重试。优点:消息数据独立存储,降低了业务系统与消息系统的耦合度。吞吐量优于本地消息表方案。缺点:发送一条消息需要两次网络请求(半条消息+commit/rollback)。需要实现消息回传接口。事实上,每种分布式事务解决方案都有优点和缺点。我们需要权衡利弊,选择最适合业务场景的才是王道!好吧。今天就到这里吧,我会继续分享我的所学所想,希望我们一起走在成功的路上!本文转载自微信公众号《狼王编程》,可通过以下二维码关注。转载本文请联系狼王编程公众号。
