`
maosheng
  • 浏览: 550261 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

事务和一致性:从ACID到CAP再到BASE

阅读更多
    先了解一下互联网时代的特点,互联网时代信息量巨大、需要计算能力巨大,不但对用户响应速度要求快,而且吞吐量指标也要向外扩展(既:水平伸缩),于是单节点的服务器无法满足需求,服务节点开始池化,但是服务节点多也不一定能解决所有事情,还得进行有序、合理的分配任务,进行有效的管理,于是互联网时代谈论最多的话题就是拆分,拆分一般分为“水平拆分”和“垂直拆分”

    这里,“水平拆分”指的是同一个功能由于单机节点无法满足性能需求,需要扩展成为多节点,多个节点具有一致的功能,组成一个服务池,一个节点服务一部分的请求量,团结起来共同处理大规模高并发的请求量。

    “垂直拆分”指的是按照功能拆分,秉着“专业的人干专业的事儿”的原则,把一个复杂的功能拆分到多个单一的简单的元功能,不同的元功能组合在一起,和未拆分前完成的功能是一致的,由于每个元功能职责单一、功能简单,让维护和变更都变得更简单、安全,更易于产品版本的迭代,在这样的一个互联网的时代和环境,一致性指分布式服务化系统之间的弱一致性,包括应用系统一致性和数据一致性。

    无论是水平拆分还是垂直拆分,都解决了特定场景下的特定问题,凡事有好的一面,都会有坏的一面,拆分后的系统或者服务化的系统最大的问题就是一致性问题,这么多个具有元功能的模块,或者同一个功能池中的多个节点之间,如何保证他们的信息是一致的、工作步伐是一致的、状态是一致的、互相协调有序的工作呢?

一个事务是指对数据库状态进行改变的一系列操作变成一个单个序列逻辑元操作,一个真正事务应该遵循ACID属性,ACID事务才真正解决事务。

一、ACID

ACID是传统数据库常用的设计理念,追求强一致性模型。

关系数据库的ACID模型拥有 高一致性 + 可用性 很难进行 分区,典型的关系型数据库Oracle、Mysql 都能保证强一致性,Oracle和Mysql使用多版本控制协议实现。

ACID分别是Atomicity 原子性、Consistency 一致性、Isolation 隔离性、Durability 持久性,有了这几个特性,就保证了数据库的可靠。

ACID模型要求一个事物必须满足上面的四点,这是对关系型传统数据库的指导性依据。而非关系型数据库NoSql则不再依赖这一模型。

1)原子性
原子性代表一个事务的所有系列操作步骤被看成是一个动作,所有的步骤要么全部完成要么一个也不会完成,如果事务过程中任何一点失败,将要被改变的数据库记录就不会被真正被改变。比如,在银行转账,从一个账号扣钱,另一个账号加钱,这两个操作必须同时进行。否则就会出现账目对不上的情况。

2)一致性:
一致性官方的描述是,事务执行后必须是从一个一致性状态转到另一个一致性状态。通俗点说就是保证整个系统在操作完成后,虽然处于不同状态,但仍保持一致。比如在转账情境中,从一个账号转出500,转入另一个账号,那么整个系统的金额不应该有变化。

3)隔离性:
隔离性意味着多个并发之间是不可见的,相互隔离不被打扰。隔离性在数据库操作中还是很重要的,如果不考虑隔离性,可能会出现下面的问题:

脏读:事务T1读取了事务T2未提交的数据,结果事务T2回滚了,T1拿到了一个脏数据
不可重复读:事务T1读取数据后,紧接着事务T2就更新了数据,事务T1再次读取的时候发现数据不一致了

幻读:这种一般发生在大批量修改的时候,比如事务T1把所有的数据从1修改到了2,结果修改的过程中,事务T2插入了一条新数据1。最后检查数据发现有一条数据没有修改过来。
针对这几种情况,数据库如Mysql提供了几种事务的隔离级别:

事务的隔离级别(5个):
ISOLATION_DEFAULT
ISOLATION_READ_UNCOMMITTED:会产生脏读,不可重复读和幻像读
ISOLATION_READ_COMMITTED:可以避免脏读出现,但是可能会出现不可重复读和幻像读
ISOLATION_REPEATABLE_READ:可以防止脏读,不可重复读。但是可能出现幻像读
ISOLATION_SERIALIZABLE:可以防止脏读,不可重复读外,还避免了幻像读

事务传播行为(7个):
PROPAGATION_REQUIRED 如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务;PROPAGATION_REQUIRED应该是我们首先的事务传播行为。它能够满足我们大多数的事务需求。

PROPAGATION_SUPPORTS 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行

PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。

PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。

PROPAGATION_NOT_SUPPORTED 总是非事务地执行,并挂起任何存在的事务。

PROPAGATION_NEVER 总是非事务地执行,如果存在一个活动事务,则抛出异常

PROPAGATION_NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行


4)持久性:
这种最容易理解了,事务提交后,结果就保存不变了。


二、CAP
CAP是分布式系统中进行平衡的理论,CAP分别是Consistency 一致性、Availability 可用性、Partition Tolerance 分区容错性。

Consistency 一致性,强调进群节点中数据一致。在分布式中一致性又包括强一致性和弱一致性,强一致性就是指在任何时刻任何节点看到的数据都是一样的;弱一致性一般实现是最终一致性,即刚开始可能存在差异,但随着时间的推移,最终数据保持一致。

Availability 可用性,强调集群在任何时间内都正常使用,所有在分布式系统活跃的节点都能够处理操作且能响应查询。

Partition Tolerance 分区容错性,即使某一部分集群坏掉,另一部分仍能正常工作。

这三个特性只能满足其中两个,牺牲另一个。大部分系统也都是如此:


一般来说分布式集群都会保证P优先,即集群部分节点坏死不影响整个集群的使用,然后再去追求C和A。因为如果放弃P——分区可用性,那不如就直接使用多个传统数据库了。事实上,很多微服务分库分表就是这个道理。

如果追求强一致性,那么势必会导致可用性下降。比如在Master-Slave的场景中,Master负责数据写入,然后分发给各个节点,所有节点都写入成功,才算写入,这样保证了强一致性,但是延迟也会随之增加,导致可用性降低。

因此在可用性和一致性之间,就出现了各种解决方案,如时序一致性、最终一致性等等。


三、BASE
前面由于分布式在CAP面前各种纠结,因此有人总结出了一套适合分布式的理论——BASE

BASE是指 基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)。

BA,Basically Available 基本可用 是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。比如降低性能要求、或者功能特性来保证整体的服务可用。比如服务的降级、增加延迟、等待等等。

电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务,这就是损失部分可用性的体现。

S,Soft State 软状态,允许系统存在中间状态,而该中间状态不会影响系统整体可用性。比如节点的不同副本之间同步存在延迟

分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication的异步复制也是一种体现。

E,Eventual Consistency 最终一致性,最终一致性是指系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。具体的方案有很多,如因果一致性、读己一致性、会话一致性、单调读一致、单调写一致。

BASE强调牺牲高一致性,从而获得可用性,数据允许在一段时间内的不一致,只要保证最终一致就可以了。


弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。

对于这几种一致性,可以简单的说一下:
因果一致性:进程B对进程A有依赖关系,那么B读取到的应该总是A更新后的值
读己一致性:进程A更新某个值后,它自己读到的应该是最新的值
会话一致性:在会话中进行操作,需要保证总是读取到最新的值
单调读一致:从系统读取某个值后,不应该读取到比它还旧的值
单调写一致:同一个进程对系统的写操作,需要保证顺序

BASE和ACID代表两种截然相反的设计理念,ACID注重一致性,是传统关系型数据库(MySQL)的设计思路,BASE关注高可用性



为了保障系统的可用性,互联网系统大多将强一致性需求转换成最终一致性的需求,并通过系统执行幂等性的保证,保证数据的最终一致性。

经典方案 - eBay 模式:
此方案的核心是将需要分布式处理的任务通过消息日志的方式来异步执行。消息日志可以存储到本地文本、数据库或消息队列,再通过业务规则自动或人工发起重试。人工重试更多的是应用于支付场景,通过对账系统对事后问题的处理。

消息日志方案的核心是保证服务接口的幂等性。

考虑到网络通讯失败、数据丢包等原因,如果接口不能保证幂等性,数据的唯一性将很难保证。


随着业务规模不断地扩大,电商网站一般都要面临拆分之路。就是将原来一个单体应用拆分成多个不同职责的子系统。比如以前可能将面向用户、客户和运营的功能都放在一个系统里,现在拆分为订单中心、代理商管理、运营系统、报价中心、库存管理等多个子系统。

拆分首先要面临的是什么呢?

最开始的单体应用所有功能都在一起,存储也在一起。比如运营要取消某个订单,那直接去更新订单表状态,然后更新库存表就 ok 了。因为是单体应用,库在一起,这些都可以在一个事务里,由关系数据库来保证一致性。

但拆分之后就不同了,不同的子系统都有自己的存储。比如订单中心就只管理自己的订单库,而库存管理也有自己的库。那么运营系统取消订单的时候就是通过接口调用等方式来调用订单中心和库存管理的服务了,而不是直接去操作库。这就涉及一个『分布式事务』的问题。


分布式事务有两种解决方式:

1)优先使用异步消息。

使用异步消息 Consumer 端需要实现幂等。

幂等有两种方式,一种方式是业务逻辑保证幂等。比如接到支付成功的消息订单状态变成支付完成,如果当前状态是支付完成,则再收到一个支付成功的消息则说明消息重复了,直接作为消息成功处理。

另外一种方式如果业务逻辑无法保证幂等,则要增加一个去重表或者类似的实现。对于 producer 端在业务数据库的同实例上放一个消息库,发消息和业务操作在同一个本地事务里。发消息的时候消息并不立即发出,而是向消息库插入一条消息记录,然后在事务提交的时候再异步将消息发出,发送消息如果成功则将消息库里的消息删除,如果遇到消息队列服务异常或网络问题,消息没有成功发出那么消息就留在这里了,会有另外一个服务不断地将这些消息扫出重新发送。

2)有的业务不适合异步消息的方式,事务的各个参与方都需要同步的得到结果。这种情况的实现方式其实和上面类似,每个参与方的本地业务库的同实例上面放一个事务记录库。
比如 A 同步调用 B,C。A 本地事务成功的时候更新本地事务记录状态,B 和 C 同样。如果有一次 A 调用 B 失败了,这个失败可能是 B 真的失败了,也可能是调用超时,实际 B 成功。则由一个中心服务对比三方的事务记录表,做一个最终决定。假设现在三方的事务记录是 A 成功,B 失败,C 成功。那么最终决定有两种方式,根据具体场景:

重试 B,直到 B 成功,事务记录表里记录了各项调用参数等信息;

执行 A 和 B 的补偿操作(一种可行的补偿方式是回滚)。

对 b 场景做一个特殊说明:比如 B 是扣库存服务,在第一次调用的时候因为某种原因失败了,但是重试的时候库存已经变为 0,无法重试成功,这个时候只有回滚 A 和 C 了。

那么可能有人觉得在业务库的同实例里放消息库或事务记录库,会对业务侵入,业务还要关心这个库,是否一个合理的设计?

实际上可以依靠运维的手段来简化开发的侵入,我们的方法是让 DBA 在公司所有 MySQL 实例上预初始化这个库,通过框架层(消息的客户端或事务 RPC 框架)透明的在背后操作这个库,业务开发人员只需要关心自己的业务逻辑,不需要直接访问这个库。

总结起来,其实两种方式的根本原理是类似的,也就是将分布式事务转换为多个本地事务,然后依靠重试等方式达到最终一致性。


例如:在交易创建流程中,首先创建一个不可见订单,然后在同步调用锁券和扣减库存时,针对调用异常(失败或者超时),发出废单消息到MQ。如果消息发送失败,本地会做时间阶梯式的异步重试;优惠券系统和库存系统收到消息后,会进行判断是否需要做业务回滚,这样就准实时地保证了多个本地事务的最终一致性。


分布式最终一致性的处理方案:

1. 查询模式
  任何一个服务操作都需要提供一个查询接口,用来向外部输出操作执行的状态。服务操作的使用方可以通过查询接口,得知服务操作执行的状态,然后根据不同状态来做不同的处理操作。
  为了能够实现查询,每个服务操作都需要有唯一的流水号标识,也可使用此次服务操作对应的资源ID来标志,例如:请求流水号、订单号等。
  首先,单笔查询操作是必须提供的,我们也鼓励使用单笔订单查询,这是因为每次调用需要占用的负载是可控的,批量查询则根据需要来提供,如果使用了批量查询,需要有合理的分页机制,并且必须限制分页的大小,以及对批量查询的QPS需要有容量评估和流控等。
  

2. 补偿模式
  有了上面的查询模式,在任何情况下,我们都能得知具体的操作所处的状态,如果整个操作处于不正常的状态,我们需要修正操作中有问题的子操作,这可能需要重新执行未完成的子操作,或者取消已经完成的子操作,通过修复使整个分布式系统达到一致,为了让系统最终一致而做的努力都叫做补偿。

补偿操作根据发起形式分为:

自动恢复:程序根据发生不一致的环境,通过继续未完成的操作,或者回滚已经完成的操作,自动来达到一致

通知运营:如果程序无法自动恢复,并且设计时考虑到了不一致的场景,可以提供运营功能,通过运营手工进行补偿

通知技术:如果很不巧,系统无法自动回复,又没有运营功能,那必须通过技术手段来解决,技术手段包括走数据库变更或者代码变更来解决,这是最糟的一种场景


3. 异步确保模式
  异步确保模式是补偿模式的一个典型案例,经常应用到使用方对响应时间要求并不太高,我们通常把这类操作从主流程中摘除,通过异步的方式进行处理,处理后把结果通过通知系统通知给使用方,这个方案最大的好处能够对高并发流量进行消峰,例如:电商系统中的物流、配送,以及支付系统中的计费、入账等。
  实践中,将要执行的异步操作封装后持久入库,然后通过定时捞取未完成的任务进行补偿操作来实现异步确保模式,只要定时系统足够健壮,任何一个任务最终会被成功执行。

  
4. 定期校对模式
  既然我们在系统中实现最终一致性,系统在没有达到一致之前,系统间的状态是不一致的,甚至是混乱的,需要补偿操作来达到一致的目的,但是我们如何来发现需要补偿的操作呢?
  在操作的主流程中的系统间执行校对操作,我们可以事后异步的批量校对操作的状态,如果发现不一致的操作,则进行补偿,补偿操作与补偿模式中的补偿操作是一致的。
  另外,实现定期校对的一个关键就是分布式系统中需要有一个自始至终唯一的ID 。

  一般情况下,生成全局唯一ID有两种方法:

持久型:使用数据库表自增字段或者Sequence生成,为了提高效率,每个应用节点可以缓存一批次的ID,如果机器重启可能会损失一部分ID,但是这并不会产生任何问题

时间型:一般由机器号、业务号、时间、单节点内自增ID组成,由于时间一般精确到秒或者毫秒,因此不需要持久就能保证在分布式系统中全局唯一、粗略递增能特点

  实践中,为了能在分布式系统中迅速的定位问题,一般的分布式系统都有技术支持系统,它能够跟踪一个请求的调用链,调用链是在二维的维度跟踪一个调用请求,最后形成一个调用树。
  
  全局的唯一流水ID可以把一个请求在分布式系统中的流转的路径聚合,而调用链中的spanid可以把聚合的请求路径通过树形结构进行展示,让技术支持人员轻松的发现系统出现的问题,能够快速定位出现问题的服务节点,提高应急效率。
  
  在分布式系统中构建了唯一ID,调用链等基础设施,我们很容易对系统间的不一致进行核对,通常我们需要构建第三方的定期核对系统,以第三方的角度来监控服务执行的健康程度。
   
  定期校对模式多应用在金融系统,金融系统由于涉及到资金安全,需要保证百分之百的准确性,所以,需要多重的一致性保证机制,包括:系统间的一致性对账、现金对账、账务对账、手续费对账等等,这些都属于定期校对模式,顺便说一下,金融系统与社交应用在技术上本质的区别在于社交应用在于量大,而金融系统在于数据的准确性。
  
  
5. 可靠消息模式
  在分布式系统中,对于主流程中优先级比较低的操作,大多采用异步的方式执行,也就是前面提到的异步确保型,为了让异步操作的调用方和被调用方充分的解耦,也由于专业的消息队列本身具有可伸缩、可分片、可持久等功能,我们通常通过消息队列实现异步化,对于消息队列,我们需要建立特殊的设施保证可靠的消息发送以及处理机的幂等等。
  

  消息的可靠发送可以认为是尽最大努力发送消息通知,有两种实现方法:
  第一种,发送消息之前,把消息持久到数据库,状态标记为待发送,然后发送消息,如果发送成功,将消息改为发送成功。定时任务定时从数据库捞取一定时间内未发送的消息,将消息发送。
  
  第二种,实现方式与第一种类似,不同的是持久消息的数据库是独立的,并不耦合在业务系统中。发送消息之前,先发送一个预消息给某一个第三方的消息管理器,消息管理器将其持久到数据库,并标记状态为待发送,发送成功后,标记消息为发送成功。定时任务定时从数据库捞取一定时间内未发送的消息,回查业务系统是否要继续发送,根据查询结果来确定消息的状态。

消息处理器的幂等性:

  如果我们要保证消息可靠的发送,简单来说,要保证消息一定要发送出去,那么就需要有重试机制,有了重试机制,消息一定会重复,那么我们需要对重复做处理。
  

处理重复的最佳方式为保证操作的幂等性,幂等性的数学公式为:
  f(f(x)) = f(x)

保证操作的幂等性常用的几个方法:

a.使用数据库表的唯一键进行滤重,拒绝重复的请求
b.使用分布式表对请求进行滤重
c.使用状态流转的方向性来滤重,通常使用行级锁来实现
d.根据业务的特点,操作本身就是幂等的,例如:删除一个资源、增加一个资源、获得一个资源等

6. 缓存一致性模型
  大规模高并发系统中一个常见的核心需求就是亿级的读需求,显然,关系型数据库并不是解决高并发读需求的最佳方案,互联网的经典做法就是使用缓存抗读需求,下面是一些使用缓存的保证一致性的最佳实践:
  

a.如果性能要求不是非常的高,尽量使用分布式缓存,而不要使用本地缓存

b.种缓存的时候一定种完全,如果缓存数据的一部分有效,一部分无效,宁可放弃种缓存,也不要把部分数据种入缓存

c.数据库与缓存只需要保持弱一致性,而不需要强一致性,读的顺序要先缓存,后数据库,写的顺序要先数据库,后缓存。










分享到:
评论

相关推荐

    分布式系统一致性(ACID、CAP、BASE、二段提交、三段提交、TCC、幂等性)原理详解1

    1背景分布式系统致性(ACID、CAP、BASE、段提交、三段提交、TCC、幂等性)原理详解-掘的是按照功能拆分,秉着 “专业的人干专业的事儿” 的原则,把

    微服务下事务一致性介绍

    微服务下事务一致性的描述,包括CAP,BASE,ACID理论,其中还包括常用的分布式事务的架构介绍,详细介绍了TCC, 最终一致性,多段提交等架构

    分布式事务解决方案「手写代码」视频教程

    1.基础概念:了解事务的ACID、CAP理论、BASE理论,为分布式方案打基础 2.2PC/3PC:通过2PC演化各种方案:XA方案、JTA、LCN、Seata 3.TCC:TCC不依赖本地事务的解决方案 4.可靠消息最终一致性:唯有了解方案原理,方能...

    Paxos到Zookeeper:分布式一致性原理与实践

    《Paxos到Zookeeper:分布式一致性原理与实践》从分布式一致性的理论出发,向读者简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了Paxos和ZAB协议。同时,本书深入介绍了分布式...

    CAP、BASE、ACID区分

    CAP、BASE、ACID区分 一、CAP CAP是分布式计算领域的公认定理。 1、一致性(Consistency) all nodes see the same data at the same time 在同一时间看见所有节点的数据是一致的 所有节点返回的数据都是一样的,...

    Paxos 到 Zookeeper:分布式一致性原理与实践 高清

    《Paxos 到 Zookeeper:分布式一致性原理与实践》从分布式一致性的理论出发,向读者简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了 Paxos 和 ZAB 协议。同时,本书深入介绍了...

    2021年数据库研究报告

    单体系统到分布式系统的变化增加了数据库实现ACID特性的难度,但许多环境下企业仍要求较强的一致性。经过多年的发展,各数据库厂商提出了多种分布式事务解决方案,例如两阶段提交(2PC)/三阶段提交(3PC)、TCC方案...

    分布式事务的七种实现方案汇总分析

    随着微服务的普及,...为了便于后文叙述,这里对ACID中的C(一致性)做一个强调:严格的事务一致性是使数据库从一个一致性状态变到另一个一致性状态,且事务中间状态不能被观察到。分布式事务的七种实现方案: 1、基

    从Paxos到Zookeeper

    《Paxos到Zookeeper:分布式一致性原理与实践》从分布式一致性的理论出发,向读者简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了Paxos和ZAB协议。同时,本书深入介绍了分布式...

    CAP理论与分布式数据库

    而传统数据库保证了强一致性(ACID模型)和高可用性,所以要想实现一个分布式数据库集群非常困难,这也解释了为什么数据库的扩展能力十分有限。而近年来不断发展壮大的NoSQL运动,就是通过牺牲强一致性,采用BASE模型...

    第10章 NoSQL数据库1

    引入BASE当处理CAP的问题时,可以有4个选择:BASE模型反ACID模型,完全不同ACID模型,牺牲高一致性,获得可用性或可靠性BASE思想主要强调基本的可

    zookeeper(一)

    分布式环境 分布式环境的特点 分布性 并发性:程序运行过程中,并发性操作是很常见的。比如同一个分布式系统中的多个节点,同时访问...分布式事务:ACID(原子性、一致性、隔离性、持久性)。 CAP/BASE理论 CAP consisten

    海量数据下的分布式存储与计算

    CAP,BASE,ACID这些原理在过去的一些年对其有着一定的指导作用(近年来随着各种实时计算模型的发展,CAP也被渐渐打破)CAP:(Consistency-Availability-PartitionTolerance数据一致性(C):等同于所有节点访问同一...

    MySQL高可用运营

    业务最终一致性,cap、base。 允许丢失和对账、异步达成。 金融业务的特性。 事物一致性,oltp、acid。 可靠性高,99.99%,53min。 大规模系统的问题。 单台设备故障导致整体不可用。 服务关联性,互相影响故障...

    大数据技术原理与应用.docx

    最终一致性 D.BASE 大数据技术原理与应用全文共10页,当前为第3页。12. 12单选(2分)在设计词频统计的MapReduce程序时,对于文本行"hello bigdata hello hadoop",经过map函数处理后直接输出的结果应该是(没有发生...

Global site tag (gtag.js) - Google Analytics