原标题:还不理解“分布式事务”?这篇给你讲清楚!
“
这篇文章将介绍什么是分布式事务,分布式事务解决什么问题,对分布式事务实现的难点,解决思路,不同场景下方案的选择,通过图解的方式进行梳理、总结和比较。
相信耐心看完这篇文章,谈到分布式事务,不再只是有“2PC”、“3PC”、“MQ的消息事务”、“最终一致性”、“TCC”等这些知识碎片,而是能够将知识连成一片,形成知识体系。
什么是事务
介绍分布式事务之前,先介绍什么是事务。
事务的具体定义
事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。
简单地说,事务提供一种“ 要么什么都不做,要么做全套(All or Nothing)”机制。
数据库事务的 ACID 属性
事务是基于数据进行操作,需要保证事务的数据通常存储在数据库中,所以介绍到事务,就不得不介绍数据库事务的 ACID 特性。
ACID 指数据库事务正确执行的四个基本特性的缩写,包含:
原子性(Atomicity)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。
事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
例如:银行转账,从 A 账户转 100 元至 B 账户,分为两个步骤:
从 A 账户取 100 元。
存入 100 元至 B 账户。
这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了 100 元。
一致性(Consistency)
在事务开始之前和事务结束以后,数据库数据的一致性约束没有被破坏。
例如:现有完整性约束 A+B=100,如果一个事务改变了 A,那么必须得改变 B,使得事务结束后依然满足 A+B=100,否则事务失败。
隔离性(Isolation)
数据库允许多个并发事务同时对数据进行读写和修改的能力,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。
隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
例如:现有有个交易是从 A 账户转 100 元至 B 账户,在这个交易事务还未完成的情况下,如果此时 B 查询自己的账户,是看不到新增加的 100 元的。
持久性(Durability)
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
简单而言,ACID 是从不同维度描述事务的特性:
原子性:事务操作的整体性。
一致性:事务操作下数据的正确性。
隔离性:事务并发操作下数据的正确性。
持久性:事务对数据修改的可靠性。
一个支持事务(Transaction)的数据库,需要具有这 4 种特性,否则在事务过程当中无法保证数据的正确性,处理结果极可能达不到请求方的要求。
什么时候使用数据库事务
在介绍完事务基本概念之后,什么时候该使用数据库事务?
简单而言,就是业务上有一组数据操作,需要如果其中有任何一个操作执行失败,整组操作全部不执行并恢复到未执行状态,要么全部成功,要么全部失败。
在使用数据库事务时需要注意,尽可能短的保持事务,修改多个不同表的数据的冗长事务会严重妨碍系统中的所有其他用户,这很有可能导致一些性能问题。
什么是分布式事务
介绍完事务相关基本概念之后,下面介绍分布式事务。
分布式产生背景与概念
随着互联网快速发展,微服务,SOA 等服务架构模式正在被大规模的使用,现在分布式系统一般由多个独立的子系统组成,多个子系统通过网络通信互相协作配合完成各个功能。
有很多用例会跨多个子系统才能完成,比较典型的是电子商务网站的下单支付流程,至少会涉及交易系统和支付系统。
而且这个过程中会涉及到事务的概念,即保证交易系统和支付系统的数据一致性,此处我们称这种跨系统的事务为分布式事务。
具体一点而言,分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
举个互联网常用的交易业务为例:
上图中包含了库存和订单两个独立的微服务,每个微服务维护了自己的数据库。
在交易系统的业务逻辑中,一个商品在下单之前需要先调用库存服务,进行扣除库存,再调用订单服务,创建订单记录。
可以看到,如果多个数据库之间的数据更新没有保证事务,将会导致出现子系统数据不一致,业务出现问题。
分布式事务的难点
事务的原子性
事务操作跨不同节点,当多个节点某一节点操作失败时,需要保证多节点操作的要么什么都不做,要么做全套(All or Nothing)的原子性。
事务的一致性
当发生网络传输故障或者节点故障,节点间数据复制通道中断,在进行事务操作时需要保证数据一致性,保证事务的任何操作都不会使得数据违反数据库定义的约束、触发器等规则。
事务的隔离性
事务隔离性的本质就是如何正确处理多个并发事务的读写冲突和写写冲突,因为在分布式事务控制中,可能会出现提交不同步的现象,这个时候就有可能出现“部分已经提交”的事务。
此时并发应用访问数据如果没有加以控制,有可能出现“脏读”问题。
分布式系统的一致性
前面介绍到的分布式事务的难点涉及的问题,最终影响是导致数据出现不一致,下面对分布式系统的一致性问题进行理论分析,后面将基于这些理论进行分布式方案的介绍。
可用性和一致性的冲突:CAP 理论
CAP 定理又被称作布鲁尔定理,是加州大学的计算机科学家布鲁尔在 2000 年提出的一个猜想。
2002 年,麻省理工学院的赛斯·吉尔伯特和南希·林奇发表了布鲁尔猜想的证明,使之成为分布式计算领域公认的一个定理。
布鲁尔在提出 CAP 猜想时并没有具体定义 Consistency、Availability、Partition Tolerance 这 3 个词的含义,不同资料的具体定义也有差别。
为了更好地解释,下面选择Robert Greiner的文章《CAP Theorem》作为参考基础:
http://robertgreiner.com/about/
http://robertgreiner.com/2014/08/cap-theorem-revisited/
CAP 理论的定义
在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
Consistency、Availability、Partition Tolerance 具体解释如下:
C - Consistency 一致性:A read is guaranteed to return the most recent write for a given client.
对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
这里并不是强调同一时刻拥有相同的数据,对于系统执行事务来说,在事务执行过程中,系统其实处于一个不一致的状态,不同的节点的数据并不完全一致。
一致性强调客户端读操作能够获取最新的写操作结果,是因为事务在执行过程中,客户端是无法读取到未提交的数据的。
只有等到事务提交后,客户端才能读取到事务写入的数据,而如果事务失败则会进行回滚,客户端也不会读取到事务中间写入的数据。
A - Availability 可用性:A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).
非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。
这里强调的是合理的响应,不能超时,不能出错。注意并没有说“正确”的结果,例如,应该返回 100 但实际上返回了 90,肯定是不正确的结果,但可以是一个合理的结果。
P - Partition Tolerance 分区容忍性:The system will continue to function when network partit