引言

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

什么是分布式事务

简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

优点:

XA接口标准化、使用简单,使用成本也很低;

缺点:

性能不理想,很难满足互联网大并发需求。开销大,分布式事务RT相较于单机事务有数量级的差距;分布式事务对相关资源的加锁机制增加了并发冲突,影响到系统吞吐和可伸缩性;

XA要求资源管理必须实现XA接口,对资源管理器提出了要求,限制了业务方的产品选型;在Mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

分布式事务的应用场景

支付

最经典的场景就是支付了,一笔支付,是对买家账户进行扣款,同时对卖家账户进行加钱,这些操作必须在一个事务里执行,要么全部成功,要么全部失败。而对于买家账户属于买家中心,对应的是买家数据库,而卖家账户属于卖家中心,对应的是卖家数据库,对不同数据库的操作必然需要引入分布式事务。

在线下单

买家在电商平台下单,往往会涉及到两个动作,一个是扣库存,第二个是更新订单状态,库存和订单一般属于不同的数据库,需要使用分布式事务保证数据一致性。

常见的分布式事务解决方案

基于XA协议的两阶段提交

XA是一个分布式事务协议,由Tuxedo提出。XA中大致分为两部分:事务管理器和本地资源管理器。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA实现分布式事务的原理如下:

总的来说,XA协议比较简单,而且一旦商业数据库实现了XA协议,使用分布式事务的成本也比较低。但是,XA也有致命的缺点,那就是性能不理想,特别是在交易下单链路,往往并发量很高,XA无法满足高并发场景。XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想,mysql的XA实现,没有记录prepare阶段日志,主备切换回导致主库与备库数据不一致。许多nosql也没有支持XA,这让XA的应用场景变得非常狭隘。

分布式事务定义

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

标准模式

读未提交(read uncommitted)和读已提交(read committed),其中读未提交是缺省设置

Read uncommitted

标准模式在读未提交的隔离级别下,存在脏写,脏读的风险。

脏写出现的概率很低,只有以下几个条件同时满足才会出现:

A) 事务1修改了T表的一行记录;

B) 事务2接着也修改了T表的同一行记录;

C) 事务1因为某种原因需要回滚

上面3个条件同时满足时,事务1回滚失败,出现脏写情况,这时事务系统告警模块会通知到业务人员,需要根据系统的Undo日志进行恢复。为什么说发生概率很低?一个分布式事务完成时间通常是毫秒级,两个分布式事务在这么短时间内并发修改同一行记录概率很低,假设万分之一;事务失败的概率假设也是万分之一,则出现脏写的概率是亿分之一,可以说概率非常低了。

脏写出现概率极低,即使出现,由于在业务库上记录了详细的undo/redo log,手工恢复代价也通常较小;所以脏写问题对绝大多数应用场景的负面影响可以忽略,建议采用这种读未提交的隔离级别,比读已提交级别有更好的性能。

脏读指用户读到了分布式事务的中间状态。对于成功的分布式事务,这种中间状态基本可以认为是没有负面影响的;对于失败的分布式事务,也只有很少的场景下会有负面影响,因为这种中间状态持续时间很短(通常是毫秒级),用户很难感知。即使用户看到了中间状态,通常也是能够理解的,因为他知道自己事务失败了。

标准模式的“读未提交”隔离级别是的主流应用,它兼顾了易用性与较高的性能,适用于多数分布式事务场景

Read committed

标准模式在读已提交的隔离级别下,将对所管理的所有读已提交的分布式事务,进行写入记录的行级锁检查,当发现锁冲突,采用重试策略(最长550ms),如果经过重试后还是拿不到锁,将拒绝后进的事务,并将异常抛出给上层业务系统。

需要说明的是:仅能保证被管理的读已提交的事务间的Read Committed的隔离性。

隔离级别可以通过的RM配置项进行设置。

读已提交隔离级别比读未提交增大了开销(10%~20%),如果select语句也采用读已提交则会有更大开销。如4.1.1所分析,实际业务场景下,读未提交是足够安全的,不建议使用读已提交隔离级别。

分布式事务原理:分段式提交

分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。分布式事务通过2PC协议将提交分成两个阶段:

prepare;

commit/rollback

阶段一为准备(prepare)阶段。即所有的参与者准备执行事务并锁住需要的资源。参与者ready时,向transaction manager报告已准备就绪。

阶段二为提交阶段(commit)。当transaction manager确认所有参与者都ready后,向所有参与者发送commit命令。

如下图所示:

事务协调者transaction manager

因为XA 事务是基于两阶段提交协议的,所以需要有一个事务协调者(transaction manager)来保证所有的事务参与者都完成了准备工作(第一阶段)。如果事务协调者(transaction manager)收到所有参与者都准备好的消息,就会通知所有的事务都可以提交了(第二阶段)。MySQL 在这个XA事务中扮演的是参与者的角色,而不是事务协调者(transaction manager)。

总结

以 上就是我对Java开发大型互联网架构分布式事务系统设计之分布式原理分析问题及其优化总结,分享给大家,觉得收获的话可以点个关注收藏转发一波喔,谢谢大佬们支持!

最后,每一位读到这里的网友,感谢你们能耐心地看完。希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步!都能赢取白富美,走向架构师的人生巅峰!

想了解学习Java方面的技术内容以及Java技术视频的内容可加群:722040762 验证码:头条(06 必过)欢迎大家的加入哟!

分类: 百科知识 标签: 暂无标签

评论

暂无评论数据

暂无评论数据

目录