分布式事务(一)之什么是分布式事务

分布式事务(一)之什么是分布式事务

一、事务简介

​ 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中,一个事务由一组SQL语句组成。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

1.原子(atomicity)**:可以理解为一个事务内的所有操作要么都执行,要么都不执行,不可能出现部分成功部分失败的情况。。

2.一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态,事务的中间状态不能被观察到的。可以理解为数据是满足完整性约束的,也就是不会存在中间状态的数据,比如你账上有400,我账上有100,你给我打200块,此时你账上的钱应该是200,我账上的钱应该是300,不会存在我账上钱加了,你账上钱没扣的中间状态

  1. 隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
    并发事务问题
    脏读(dirty read):读到另一个事务的未提交新数据,即读取到了脏数据;
    不可重复读(unrepeatable):对同一记录的两次读取不一致,因为另一事务对该记录做了修改;
    幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务入了一插条记录。

隔离性又分为四个级别:

  • 读未提交(read uncommitted):实质上该级别允许读取未提交的数据,就是允许脏读。如果一个事务A读取了一条记录 r,并修改了该记录,事务A尚未提交时,事务B读取了r,如果事务A最后回滚了(因某种原因),那么事务B读了一条无效的记录。[1]给的例子,如果事务A对某一个值进行了 加1 操作 10 次,事务B能读取其中的中间值 2,3,4… ,这一系列中间值的读取就是未授权读取。
  • 读已提交(read committed,解决脏读):不允许脏读了。如果事务A对读取了一条记录 r1,并修改了该记录为 r2,事务A尚未提交时,事务B读取该记录,依然是原来的 r1,当事务A committed以后,事务B才能读取事务A修改后的值 r2,这就是授权读取,不会读中间数据,只读最终提交的数据。但是,这有个问题,不可重复读问题(在一个事务范围内,执行2个相同的查询,查询的结果不同,因为有其他事务update了数据)。事务A事先读取了数据,事务B紧接了更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变 ,造成了不可重复读。
  • 可重复读(repeatable read,解决虚读)、该隔离界别是多次读取同一条记录时,读取结果相同。这是禁止了不可重复读,实质上,当事务A读取记录r1时,不允许其他事务修改 r1,如果修改,需要等待事务A处理结束。说个额外有趣的,当事务A在修改数据时,发生了查询怎么办?实际应用中,是给数据和查询加了一个SCN (System change number),简单的说,为每一个查询添加一个时间戳,然后对比记录的时间戳
  • 串行化(serializable,解决幻读)。这是最严苛的事务隔离级别。将所有事务串行化执行,简单暴力,直觉低效(但是也看场合)。
  1. 持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

任何事务机制在实现时,都应该考虑事务的ACID特性,包括:本地事务、分布式事务,即使不能都很好的满足,也要考虑支持到什么程度。

参考:

读提交和可重复读区别 https://blog.csdn.net/tolcf/article/details/49311035


二 本地事务

在没有接触分布式应用前,我们接触到的事务一般都是本地事务,即在单个数据库并且限制在单个进程内的事务。本地事务不涉及多个数据源。

本地事务的ACID特性是数据库直接提供支持。本地事务应用架构如下所示:

图片

在JDBC编程中,我们通过java.sql.Connection对象来开启、关闭或者提交事务。代码如下所示:

Connection conn = JdbcUtils.getConnection(); //获取数据库
conn.setAutoCommit(false); //开启事务
try{
   //...执行增删改查sql
   conn.commit(); //提交事务
}catch (Exception e) {
  conn.rollback();//事务回滚
}finally{
   conn.close();//关闭链接
}

此外,很多java应用都整合了spring,并使用其声明式事务管理功能来完成事务功能。

spring事务参考文章:

Spring事务管理(详解+实例)
https://blog.csdn.net/trigl/article/details/50968079
Spring事务配置的五种方式
http://www.blogjava.net/robbie/archive/2009/04/05/264003.html
Spring事务管理及几种简单的实现
https://blog.csdn.net/zhuxinquan61/article/details/71075051
Spring中事务控制的 API介绍
https://blog.csdn.net/Kato_op/article/details/80247834

三 分布式事务典型场景

  • 典型的场景就是微服务架构,微服务之间通过远程调用完成事务操作。比如:订单微服务和库存微服务,下单的同时订单微服务请求库存微服务减库存。简言之:跨JVM进程产生分布式事务
  • 单体系统访问多个数据库实例,跨数据库实例产生分布式事务
  • 多服务访问同一个数据库实例,比如:订单微服务和库存微服务即使访问同一个数据库也会产生分布式事务,原因就是跨JVM进程,两个微服务持有了不同的数据库链接进行数据库操作,此时产生分布式事务。

典型的分布式事务场景:

1、跨库事务

跨库事务指的是,一个应用某个功能需要操作多个库,不同的库中存储不同的业务数据。下图演示了一个服务同时操作2个库的情况:

图片

2、分库分表

通常一个库数据量比较大或者预期未来的数据量比较大,都会进行水平拆分,也就是分库分表。如下图,将数据库B拆分成了2个库:

图片

对于分库分表的情况,一般开发人员都会使用一些数据库中间件来降低sql操作的复杂性。如,对于sql:insert into user(id,name) values (1,“zhangshan”),(2,“lisi”)。这条sql是操作单库的语法,单库情况下,可以保证事务的一致性。

但是由于现在进行了分库分表,开发人员希望将1号记录插入分库1,2号记录插入分库2。所以数据库中间件要将其改写为2条sql,分别插入两个不同的分库,此时要保证两个库要不都成功,要不都失败,因此基本上所有的数据库中间件都面临着分布式事务的问题。

互联网公司常用分库分表方案汇总!https://zhuanlan.zhihu.com/p/137368446

3、服务化(SOA)

微服务架构是目前一个比较一个比较火的概念。例如某个应用同时操作了多个库,这样的应用业务逻辑必然非常复杂,对于开发人员是极大的挑战,应该拆分成不同的独立服务,以简化业务逻辑。拆分后,独立服务之间通过RPC框架来进行远程调用,实现彼此的通信。下图演示了一个3个服务之间彼此调用的架构:

图片

Service A完成某个功能需要直接操作数据库,同时需要调用Service B和Service C,而Service B又同时操作了2个数据库,Service C也操作了一个库。需要保证这些跨服务的对多个数据库的操作要不都成功,要不都失败,实际上这可能是最典型的分布式事务场景。

小结:上述讨论的分布式事务场景中,无一例外的都直接或者间接的操作了多个数据库。如何保证事务的ACID特性,对于分布式事务实现方案而言,是非常大的挑战。同时,分布式事务实现方案还必须要考虑性能的问题,如果为了严格保证ACID特性,导致性能严重下降,那么对于一些要求快速响应的业务,是无法接受的。

四 分布式事务基础理论

4.1 经典的分布式系统理论-CAP

2000年7月,加州大学伯克利分校的Eric Brewer教授在ACM PODC会议上提出CAP猜想。Brewer认为在设计一个大规模的分布式系统时会遇到三个特性:一致性(consistency)、可用性(Availability)、分区容错(partition-tolerance),而一个分布式系统最多只能满足其中的2项。2年后,麻省理工学院的Seth Gilbert和Nancy Lynch从理论上证明了CAP。之后,CAP理论正式成为分布式计算领域的公认定理。

图片

1. 一致性

一致性指“all nodes see the same data at the same time”,即更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致,不能存在中间状态。例如对于电商系统用户下单操作,库存减少、用户资金账户扣减、积分增加等操作必须在用户下单操作完成后必须是一致的。不能出现类似于库存已经减少,而用户资金账户尚未扣减,积分也未增加的情况。如果出现了这种情况,那么就认为是不一致的。

关于一致性,如果的确能像上面描述的那样时刻保证客户端看到的数据都是一致的,那么称之为强一致性。如果允许存在中间状态,只要求经过一段时间后,数据最终是一致的,则称之为最终一致性。此外,如果允许存在部分数据不一致,那么就称之为弱一致性。

2. 可用性

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。“有限的时间内”是指,对于用户的一个操作请求,系统必须能够在指定的时间内返回对应的处理结果,如果超过了这个时间范围,那么系统就被认为是不可用的。试想,如果一个下单操作,为了保证分布式事务的一致性,需要10分钟才能处理完,那么用户显然是无法忍受的。“返回结果”是可用性的另一个非常重要的指标,它要求系统在完成对用户请求的处理后,返回一个正常的响应结果,不论这个结果是成功还是失败。

3. 分区容错性

分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。

小结:既然一个分布式系统无法同时满足一致性、可用性、分区容错性三个特点,我们就需要抛弃一个,需要明确的一点是,对于一个分布式系统而言,分区容错性是一个最基本的要求。因为既然是一个分布式系统,那么分布式系统中的组件必然需要被部署到不同的节点,否则也就无所谓分布式系统了。而对于分布式系统而言,网络问题又是一个必定会出现的异常情况,因此分区容错性也就成为了一个分布式系统必然需要面对和解决的问题。因此系统架构师往往需要把精力花在如何根据业务特点在C(一致性)和A(可用性)之间寻求平衡。而前面我们提到的X/Open XA 两阶段提交协议的分布式事务方案,强调的就是一致性;由于可用性较低,实际应用的并不多。而基于BASE理论的柔性事务,强调的是可用性,目前大行其道,大部分互联网公司采可能会优先采用这种方案。

4.2 BASE理论

a)强一致性与最终一致性
  • 强一致性:CAP中的一致性要求在任何时间查询每个结点数据都必须一致,它强调的是强一致性。
  • 最终一致性:允许可以在一段时间内每个结点的数据不一致,但是经过一段时间每个结点的数据必须一致,它强调的是最终数据的一致性。
b)概念

BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)三个短语的缩写。BASE理论是对CAP中AP的一个扩展,通过牺牲强一致性来获得可用性,当出现故障允许部分不可用但要保证核心功能可用,允许数据在一段时间内是不一致的,但最终达到一致状态。满足BASE理论的事务,我们称之为“柔性事务”。

  • 基本可用:分布式系统在出现故障时,允许损失部分可用功能,保证核心功能可用。如,电商网站交易付款出现问题了,商品依然可以正常浏览。

  • 软状态:由于不要求强一致性,所以BASE允许系统中存在中间状态(也叫软状态),这个状态不影响系统可用性,如订单的“支付中”、“数据同步中”等状态,待数据最终一致后状态改为“成功”状态。

  • 最终一致性:最终一致是指经过一段时间后,所有节点数据都将会达到一致。如订单的"支付中"状态,最终会变为“支付成功”或者"支付失败",使订单状态与实际交易结果达成一致,但需要一定时间的延迟、等待。

    BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物ACID特性是相反的。它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID特性和BASE理论往往又会结合在一起。

4.3 典型的柔性事务方案

最大努力通知(非可靠消息、定期校对)

可靠消息最终一致性(异步确保型)

TCC(两阶段型、补偿型)

参考文档:

http://www.hollischuang.com/archives/666

http://www.cnblogs.com/hxsyl/p/4381980.html

http://blog.csdn.net/hu_zhiting/article/details/77060582

https://www.zhihu.com/question/31813039

https://my.oschina.net/foodon/blog/372703

http://blog.jobbole.com/95632/

http://www.jianshu.com/p/6c1fd2420274

http://www.linuxidc.com/Linux/2015-11/124942.htm

https://www.cnblogs.com/bbgs-xc/p/14456917.html#_label0_3

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值