文章有点长,铁子们耐心观看,一次看不完的可以收藏有时间再看,如果遇到类似的问题,希望这篇文章能帮助到你
在分布式、微服务大行其道的今天,分布式事务永远都是绕不开的一个话题。相信大家对这些名词都不会陌生。而说到使用分布式,或者拆分微服务的好处,你肯定能想到一大堆。比如每个人只需要维护自己单独的服务,没有了以前的各种代码冲突。自己想测试、想发布、想升级,只需要care自己写的代码就OK了,很方便很贴心!然而事物都有两面性,但是它也同时也会带来的一些问题,今天的文章谈的就是分布式系统架构带来的其中一个棘手的问题:分布式事务
我们都知道数据库的事务满足"ACID"特性,A是指事务的原子性,C是指事务的一致性,I指事务的隔离性,D指持久性。
最开始我们的数据量都很小,所有的数据都落在一个数据库中。MySQL数据库单表的最大数据量在百万条左右,随着系统变大,数据越来越多,这个时候我们不得不将数据分布在不同的数据库中存放,也就是常说的数据分片(sharding)。我们可以通过一定的分库策略将同一个交易链路上的数据放到一个数据库中,例如我们可以将一个订单所有产生的数据放到一个数据库中,按照订单号来分库,这样我们在生成订单相关数据的时候可以在单个数据库上开启事务来完成。
一、什么是分布式事务
介绍分布式事务之前,先介绍什么是事务。
简单的来说就是,一个大的操作由两个或者更多的小的操作共同完成。而这些小的操作又分布在不同的网络主机上。这些操作,要么全部成功执行,要么全部不执行。
事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。
简单地说,事务提供一种“ 要么什么都不做,要么做全套(All or Nothing)”机制。
拿转账的例子来说下什么是分布式事务。张三和李四在不同的城市,存储他们账户信息的服务器也在不同的网络主机上。张三有30元钱,李四有30元钱。张三给李四转账5元就是一个事务。
完成这个事务,需要两个操作。首先得从张三账户上扣5元,然后再给李四账户上加5元。事务执行完毕后,必须是两个操作都执行成功,要么都失败。
事务的特性
分布式事务本身就是事务,所以也有事务的特性。事务有四个特征ACID:
原子性(Atomicity):事务中的各个操作单元要么全部做,要么就全部不做。不能事务执行后,处于只做一半的状态。
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。
事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
例如:银行转账,从 A 账户转 100 元至 B 账户,分为两个步骤:
- 从 A 账户取 100 元。
- 存入 100 元至 B 账户。
这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了 100 元。
一致性(Consistency):事务执行后,必须由一个一致状态变为另外一个一致状态。
在事务开始之前和事务结束以后,数据库数据的一致性约束没有被破坏。
例如:现有完整性约束 A+B=100,如果一个事务改变了 A,那么必须得改变 B,使得事务结束后依然满足 A+B=100,否则事务失败。
隔离性(Isolation):事务之间不能相互干扰。
数据库允许多个并发事务同时对数据进行