分布式事务初识

Posted by BY KiloMeter on January 28, 2019

什么是分布式事务

这里先解释下什么是事务,学过数据库原理的都知道,事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。

事务有以下四个性质(ACID)

  • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。

  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。

​ 事务可以不同程度的一致性:

强一致性:读操作可以立即读到提交的更新操作。

弱一致性:提交的更新操作,不一定立即会被读操作读到,此种情况会存在一个不一致窗口,指的是读操作可以读到最新值的一段时间。

最终一致性:是弱一致性的特例。事务更新一份数据,最终一致性保证在没有其他事务更新同样的值的话,最终所有的事务都会读到之前事务更新的最新值。如果没有错误发生,不一致窗口的大小依赖于:通信延迟,系统负载等。

​ 其他一致性变体还有:

单调一致性:如果一个进程已经读到一个值,那么后续不会读到更早的值。

会话一致性:保证客户端和服务器交互的会话过程中,读操作可以读到更新操作后的最新值。

隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。

​ 比如一个事务不会读取到另一个未提交事务修改的数据。在事务的并发操作中可能会出现以下几种情况:

脏读:事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。

不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。

幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。 ​ 事务的隔离级别从低到高有:

Read Uncommitted(读取未提交内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。

Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。

Repeated Read(可重读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。

Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

​ 通常,在工程实践中,为了性能的考虑会对隔离性进行折中。

持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。

当任意一个步骤失败时,所有步骤的操作结果都会被取消,从而保证了事务的原子性 。原子性 通过保证系统数据永远不会处于不一致或部分完成的状态来确保一致性 。隔离性同样确保了一致性 。最后,所有结果是持久化 的,提交到数据存储中。在发生系统崩溃或其他灾难性事情的时候,不用担心事务的结果丢失。

事务的实现以及关于锁和MVCC等内容可以参考以下

数据库事务与MySQL事务总结

MySQL锁总结

下面在正式进入分布式事务讨论前,先介绍一个新的理论CAP理论

CAP理论

一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

这篇博客有一个关于CAP理论的例子,比较容易理解CAP 理论 —— 最通俗的解释

这篇博客写的也很不错~,有CAP理论的证明,以及CAP中,什么业务情况下需要优先选择哪两个性质

分布式系统的CAP理论

一致性(Consistency)指更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致。

对于一致性,有三种一致性模型:

  • 强一致性:要求无论更新操作是在哪个数据副本上执行,之后所有的读操作都要能获得最新的数据。

    对于单副本数据来说,读写操作是在同一数据上执行的,容易保证强一致性。对多副本数据来说,则需要使用分布式事务协议。

  • 弱一致性:在这种一致性下,用户读到某一操作对系统特定数据的更新需要一段时间,我们将这段时间称为”不一致性窗口”。

  • 最终一致性:是弱一致性的一种特例,在这种一致性下系统保证用户最终能够读取到某操作对系统特定数据的更新(读取操作之前没有该数据的其他更新操作)。

    “不一致性窗口”的大小依赖于交互延迟、系统的负载,以及数据的副本数等。

CAP中的一致性指的是强一致性。

可用性(Availability)指的是服务一直是能够对外提供服务的。

分区容错性(Partition tolerance)指分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。

分区容错性可能不好理解,这里我们可以倒推一下:

为了保证一致性,我们需要各个节点同步消息

为了保证可用性我们可以多部署节点,部分节点挂了仍可对外提供服务

为了保证分区容忍性:此刻卡壳了,怎么做?没了一种具体的方式,然而他还是客观存在的

后来发现:进入了思维盲点:只要在分布式场景中,分区必然存在,那么如果不处理分区发生时的情况,节点无法通讯时会发生什么?–此刻如果仍对外提供服务,那么导致无法同步消息,即保证不了强一致性;如果要保证强一致性,那么就需要节点阻塞,一直等待通讯恢复,即保证不了可用性.

所以分区容忍性就是:当发生分区问题时,我们使用策略,在一致性和可用性二者间选择

注意: 无法通信包括网络问题,或者节点机器宕机

误区: CAP理论中说三者不可兼得,但实际情况是,在分布式场景中分区一定存在,即必须有分区容忍性对应的策略,之后才能在一致性和可用性间二者之间选择.所以对主流架构来说不是三选二,而是二选一。

CAP之间的三选二是在分区发生问题时无法保证三者同时满足,不是意味着啥也不做,当分区的问题解决后,系统还是要保持CAP的。

在分布式系统中,我们往往追求的是可用性,对于一致性而言,可以采用适当的方式达到最终一致性。

这里又引出了另一个理论:BASE理论。

BASE理论

BASE理论的内容指的是:

  • Basically Available(基本可用)

    分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。

    这里的关键词是“部分”和“核心”,实际实践上,哪些是核心需要根据具体业务来权衡。

    例如登录功能相对注册功能更加核心,注册不了最多影响流失一部分用户,如果用户已经注册但无法登录,那就意味着用户无法使用系统,造成的影响范围更大。

  • Soft state(软状态)

    允许系统存在中间状态,而该中间状态不会影响系统整体可用性。这里的中间状态就是 CAP 理论中的数据不一致。

  • Eventually consistent(最终一致性)

    系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。

    这里的关键词是“一定时间” 和 “最终”,“一定时间”和数据的特性是强关联的,不同业务不同数据能够容忍的不一致时间是不同的。

    例如支付类业务是要求秒级别内达到一致,因为用户时时关注;用户发的最新微博,可以容忍 30 分钟内达到一致的状态,因为用户短时间看不到明星发的微博是无感知的。

    而“最终”的含义就是不管多长时间,最终还是要达到一致性的状态。

BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。