事务从集中式到分布式的转变

来源:互联网 发布:数控火焰切割编程代码 编辑:程序博客网 时间:2024/06/05 13:08

分布式环境的几个问题

下面简要的说几个分布式环境中典型的问题:

  • 通信异常
    从集中式向分布式演变的过程中,必然引入了网络因素,而由于网络本身的不可靠性,因此也引入了额外的问题。分布式系统需要在各个节点之间进行网络通信,因此每次网络通信都会伴随着网络不可用的风险。另外,即使分布式系统各节点之间的网络通信能够正常进行,其延时也会远大于单机操作。因此,消息丢失和消息延迟变得非常普遍。

  • 网络分区
    当网络由于发生异常情况,导致分布式系统中部分节点之间的网络延时不断增大,最终导致组成分布式系统的所有节点中,只有部分节点之间能够进行正常通行,而另一些节点则不能——我们将这个现象称为网络分区,就是俗称的“脑裂”。当网络分区出现时,分布式系统会出现局部小集群,在极端情况下,这些局部小集群会独立完成原本需要整个分布式系统才能完成的功能,包括对数据的事务处理,这就对分布式一致性提出了非常大的挑战。

  • 三态
    在分布式环境下,网络可能会出现各式各样的问题,因此分布式系统的每一次请求与响应,存在特有的“三态”:成功、失败与超时。在分布式系统中,由于网络是不可靠的,虽然在绝大部分情况下,网络通信也能够接收到成功或者失败的响应,但是当网络出现异常的情况下,就可能会出现超时现象,通常有两种情况:1、请求消息发送过程中出现了消息丢失现象;2、响应消息发送过程中丢失。当出现这样的超时现象时,网络通信的发起方是无法确定当前请求是否被成功处理的。

  • 节点故障
    节点故障则是分布式环境下另一个比较常见的问题,指的是组成分布式系统的服务器节点出现宕机或者“僵死”现象。

从 ACID 到 CAP/BASE

下面看看在分布式系统事务处理与数据一致性上遇到的一些挑战。

ACID

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元,狭义上的事务特指数据库事务。一方面,当多个应用程序并发访问数据库时,事务可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。另一方面,事务为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持数据一致性的方法。
事务具有四个特征,分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称为事务的ACID特性。

  • 原子性
    事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,只允许出现以下两种状态之一。

    • 全部成功执行
    • 全部不执行
  • 一致性
    事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。也就是说,事务执行的结果必须是使数据库从一个一致性状态转变到另一个一致性状态。

  • 隔离性
    事务的隔离性是指在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他事务干扰。也就是说,不同的事务并发操作相同的数据时,每个事务都有各自完整的数据空间,即一个事务内部的操作及使用的数据对其他事务是隔离的,并发执行的各个事务执行不能互相干扰。
    在标准 SQL 规范中,定义了4个事务隔离级别,不同的隔离级别对事务处理不同,分别是:未授权读取、授权读取、可重复读取和串行化。

    1. 未授权读取
      也被称为读未提交(Read Uncommitted),该隔离级别允许脏读取,其隔离级别最低。换句话说,如果一个事务正在处理某一数据,并对其进行了更新,但同时尚未完成事务,因此还没有进行事务提交;而与此同时,允许另一个事务也能够访问该数据。
    2. 授权读取
      也被称为读已提交(Read Committed),它和未授权读取很相似,唯一的区别就是授权读取只允许获取已经被提交的数据。允许不可重复读取。
    3. 可重复读取
      可重复读取(Repeatable Read),简单来说,就是保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻是一致的。
    4. 串行化
      串行化(Serializable)是最严格的事务隔离级别。它要求所有事务都被串行执行,即事务只能一个接一个地进行处理,不能并发执行。

    事务的隔离级别越高,就越能保证数据的完整性和一致性,但同时对并发性能的影响也就越大。通常,对于绝大多数的应用程序来说,可以优先考虑将数据库系统的隔离级别设置为授权读取,这能够在避免脏读取的同时保证较好的并发性能。尽管这个事务隔离级别会导致不可重复读、虚读和第二类丢失更新等并发问题,但较为科学的做法是在可能出现这类问题的个别场合中,由应用程序主动采用悲观锁或乐观锁来进行事务控制。

  • 持久性
    事务的持久性也被称为永久性,是指一个事务一旦提交,它对数据库中对应数据的状态变更就应该是永久性的。即使发生系统崩溃或者机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束时的状态。

分布式事务

在单机数据库中,很容易能够实现一套满足 ACID 特性的事务处理系统,但在分布式数据库中,数据分散在各台不同的机器上,如何对这些数据进行分布式的事务处理具有非常大的挑战。

分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于分布式系统的不同节点之上。通常一个分布式事务中会涉及对多个数据源或业务系统的操作。

一个分布式事务可以看作是由多个分布式的操作序列组成的,通常可以把这一系列分布式的操作系列称为子事务。因此,分布式事务也可以被定义为一种嵌套型的事务,同时也就具有了 ACID 事务特性。但由于在分布式事务中,各个子事务的执行是分布式的,因此要实现一种能够保证 ACID 特性的分布式事务处理系统就显得格外复杂。

CAP 和 BASE 理论

对于本地事务处理或者是集中式的事务处理系统,很显然我们可以采用已经被实践证明很成熟的 ACID 模型来保证数据的严格一致性。但是随着分布式事务的出现,传统的单机事务模型已经无法胜任。尤其是对于一个高访问量、高并发量的互联网分布式系统来说,如果我们期望实现一套严格满足 ACID 特性的分布式事务,很可能出现的情况就是在系统的可用性和严格一致性之间出现冲突。于是,如何构建一个兼顾可用性和一致性的分布式系统成为了无数工程师探讨的难题,出现了诸如 CAP 和 BASE 这样的分布式系统经典理论。

CAP 定理

理论:一个分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容错性(P:Partition tolerance)这三个基本要求,最多只能同时满足其中的两项。

一致性

在分布式环境中,一致性是指数据在多个副本之间是否能够保持一致的特性。如果能够做到针对一个数据项的更新操作执行成功后,所有的用户都可以读取到其最新的值,那么这样的系统就被认为具有强一致性(或严格的一致性)。

可用性

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。

  • 有限的时间内
    对于用户的一个操作请求,系统必须能够在指定的时间内返回相应的处理结果,如果超出这个时间范围,那么系统就被认为是不可用的。

  • 返回结果
    正常的相应结果,能够明确地反映出对请求的处理结果,即成功或失败,而不是一个让用户感到困惑的返回结果。

分区容错性

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

网络分区故障是指在分布式系统中,不同的节点分布在不同的子网络中,由于一些特殊的原因导致这些子网络之间出现网络不连通的情况,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成了若干个孤立的区域。

以上就是对 CAP 定理中一致性、可用性和分区容错性的解释。既然一个分布式系统无法同时满足上述三个需求,那么在进行对其应用时,就需要抛弃其中的一项。

放弃的特性 说明 放弃 P 如果希望能够避免系统出现分区容错性问题,一种较为简单的做法是将所有的数据都放在一个分布式节点上。这样的做法虽然无法100%保证系统不会出错,但至少不会碰到由于网络分区带来的负面影响。但同时需要注意的是,放弃 P 的同时也就意味着放弃了系统的可扩展性。 放弃 A 相对于放弃 P 来说,放弃可用性则正好相反,其做法是一旦系统遇到网络分区或其他故障时,那么受到影响的服务需要等待一定的时间,因此在等待期间系统无法对外提供正常的服务,即不可用。 放弃 C 这里说的放弃一致性,并不是完全不需要数据一致性,如果真是这样的话,那么系统的数据都是没有意义的,整个系统也是没有价值的。这里是指的放弃数据的强一致性,而保留数据的最终一致性。这样的系统无法保证数据保持实时的一致性,但是能够承诺的是,数据最终会达到一个一致的状态。

从 CAP 定理中我们可以看出,一个分布式系统不可能同时满足一致性、可用性和分区容错性这三个需求。另一方面,需要明确的是,对于一个分布式系统而言,分区容错性可以说是一个最基本的要求。为什么这样说,其实很简单,因为既然是一个分布式系统,那么分布式系统中的组件必然需要被部署到不同的节点,否则也就无所谓分布式系统了,因此必然出现子网络。而对于分布式系统而言,网络问题又是一个必定会出现的异常情况,因此分区容错性也就成为了一个分布式系统必然需要面对和解决的问题。因此系统架构设计师往往需要把精力花在如何根据业务特点在一致性和可用性之间寻求平衡。

BASE理论

BASE 是Basically Available (基本可用)、Soft state (软状态)和Eventually consistent(最终一致性)三个短语的简写,是由来自 eBay 的架构师 Dan Pritchett 在其文章 BASE:An Acid Alternative 中第一次明确提出的。BASE 是对CAP 中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,其核心思想是即使无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。接下来着重对 BASE 中的三要素进行解释。

基本可用

基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性——但注意,这绝不等价于系统不可用。以下两个就是“基本可用”的典型例子。

  • 相应时间上的损失
    响应时间由正常的0.5秒增加到了1-2秒

  • 功能上的损失
    请求量过大,引导请求到降级页面

弱状态

也称为软状态,和硬状态相对,是指允许系统中的数据存在中间状态,并认为该状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程中存在延时。

最终一致性

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

亚马逊 CEO Werner Vogels 于2008 年发表的一篇经典文章 Eventually Consistent - Revisited 中,对最终一致性进行了非常详细的介绍。他认为最终一致性是一种特殊的弱一致性:系统能够保证在没有其他新的更新操作的情况下,数据最终一定能够达到一致的状态,因此所有客户端对系统的数据访问都能够获取到最新的值。同时,在没有发生故障的前提下,数据达到一致状态的时间延迟,取决于网络延迟、系统负载和数据复制方案设计等因素。

在实际工程实践中,最终一致性存在以下五类主要变种。

  1. 因果一致性(Causal consistency)
    如果进程A在更新完某个数据项后通知了进程B,那么进程B之后对该数据项的访问都应该能够获取到进程A更新后的最新值。与此同时,与进程A无因果关系的进程C的数据访问则没有这样的限制。
  2. 读己之所写(Read your write)
    进程A更新了一个数据项之后,它自己总是能够访问到更新过的最新值。也可以看成是一种特殊的因果一致性。
  3. 会话一致性
    会话一致性将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现“读己之所写”的一致性,也就是说,执行更新操作后,客户端能够在同一个会话中始终读取到该数据项的最新值。
  4. 单调读一致性
    如果一个进程从系统中读取出一个数据项的某个值后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。
  5. 单调写一致性
    一个系统需要能够保证来自同一个进程的写操作被顺序地执行。

以上就是最终一致性的五类常见的变种,在实际系统实践中,可以将其中的若干个变种互相结合起来,以构建一个具有最终一致性特性的分布式系统。

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