ACID中C与CAP定理中C的区别

ACIDCAP定理中都有C,代表Consistent一致性,很多人容易将这两个C混为一谈,其实这两个一致性是有区别的。

事务的定义是一系列操作要么全部成功,要么全部不成功,数据库的事务机制是通过ACID实现的,数据库ACID的具体定义见这里,ACID中的一致性的定义是:一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。

也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。

如果说ACID的C是节点服务器的数据完整性,而CAP的一致性是分布式多服务器之间复制数据以取得这些服务器拥有同样的数据,这是一种分布式领域的一致性概念。因此两者是完全不同的概念。

分布式领域中的一致性有的强弱之分,强一致性也就是指一旦有写操作写入任何一个服务器,立即在其他服务器之间同步复制新的数据,这样, 任何服务器上任何读操作总是能看到最近写入的新数据。如果不能立即看到最近写入的新数据,而可能过了一段时间才能看到,则属于弱一致性或最终一致性了。

强一致性分为由写实现一致性Consistency by writes、由读实现一致性Consistency by reads和由冲裁实现一致性Consistency by Quorum。

由写实现一致性:在写入数据同时,将数据复制到其他服务器上,读取任何一台都可以获得新的写入数据,复制数据是在写操作完成,读操作轻量。

由读实现一致性:写入一旦服务器后,不再复制,而是在读取时使用版本来协调复制(如vector clock算法),这样我们简化了写操作,而将负担加在读操作。

由冲裁实现一致性:如果写入时复制到其他2/3大多数服务器,读取时也是从2/3大多数服务器读取,读取这边负责解决哪个更新是最新结果,这在读操作和写操作之间分担了负载。

回到事务话题,如果要在分布式系统中实现像ACID那样的事务机制,只有强一致性还是不够的,如果我们操作步骤顺序很重要,不可以中断或打乱,我们要么一起一次执行它们,如果并发执行这些操作步骤,无论怎么并发,也要如同它们是在独立执行,我们最终得到的结果总是相同的,这是一种更强的一致性:线性一致性linearizable consistency,类似ACID中的隔离层(serial isolation level)。

The CAP FAQ将CAP定理中的一致性定义为这种线性一致性或称为atomic原子一致性。一种比普通一致性更强的一致性,这也是大家又将ACID的C和CAP的C等同在一起的原因。ACID的C与CAP的C的关系类似精确与一致性的关系,如下图:


这种分布式的线性强一致性有两种实现方式:2PC两段提交和Paxos算法是常见两种。

通过2PC写入新数据需要经过两次来回,第一次请求commit,第二次才正式确认commit,在这两者之间过程中,所有服务器都会堵塞等待发起者发出整个事务成功还是失败的结果(只有发起者知道所有服务器的情况),如果失败,所有服务器返回之前状态,相当于写入数据失败,写入数据没有发生过一样。

而Paxos算法能够回避2PC的堵塞死锁等问题更好地实现服务器之间数据强一致复制,具体内容见:Paxos算法。也可参考比Paxos算法改进的Raft算法

参考:
Lightweight transactions in Cassandra 2.0
Distributed algorithms and protocols:Consistency
The Consistency Alphabet Soup

[该贴被banq于2015-01-02 20:00修改过]

如果A服务器确认commit成功,但是通知B服务器确认commit时,由于网络问题,无法通知B服务器确认commit;那么此时我们该怎么办?
1)如果什么都不做,那就是A服务器上的数据更新了;但是B服务器上没更新,那数据就不是强一致了;
2)如果让A服务器回滚,但假如正好也由于网络问题,无法通知A服务器回滚;那不是问题大了;这种情况下,如果允许用户继续访问A服务器上的数据,那就意味着数据不是强一致的,也就是牺牲一致性,换取可用性;如果不让用户访问A服务器上的这个数据,那就是牺牲可用性,保证强一致性;

像跨行转账这种,如果CAP中的C是指强一致性;那我认为不管用2pc,3pc,还是paxos,都是无法做到强一致性的;

当然,数据副本的强一致性是可以做到的,因为我们只要保证R+W>N即可。
而像银行转账这种,两个银行账号之间的数据强一致性(有转出必定要有转入,要么全部成功,要么全部不成功),这种一致性,我认为在分布式系统下,无法实现;

不知道banq怎么看这个问题。

首先需要区别事务与强一致性,强一致不等于事务,如同前面主贴中举例“射击靶”,事务相当于精确,一致性相当于打靶次数每次击中率都差不多,也就是说,在分布式环境中多个服务器之间的数据复制要达到一致性,一致性意味着打靶每次击中位置都差不多,排列整齐;或者服务器之间数据复制整齐一致了。

“银行转账:有转出必定要有转入,要么全部成功,要么全部不成功。”这个属于事务,只能使用2PC,2PC如果在A B两个服务器内存中包含需要修改后的新数据,并不真的改变这两个服务器后面的数据库,回滚时,如果A服务器不能访问也没关系,因为新数据只是在内存中,没有真的去修改。也就是说,2PC是事先打招呼预演一次,然后最后大家都没有问题时再commit,多几次来回,这点和Paxos算法类似。

但是Paxos算法使用两段甚至多段来回是为了在多个A服务器中复制,也就是说,2PC是在A B C...服务器之间复制数据;而Paxos算法是在A服务器多个影子之间复制,也可以在B服务器的多个影子之间复制,也可以在C服务器的多个影子之间复制,但不能将A服务器复制到B服务器。

说得再清楚些,假设A服务器是订单服务器,B服务器是库存服务器,C是支付服务器;2PC是将用户产生订单数据,A服务器新增一个订单记录,B服务器减去库存记录;C服务划账,2PC保证这个过程是事务的。而Paxos算法只是在同是订单服务器之间复制数据,比如订单服务器有10台,其中一台被用户订单新增了,那么Paxos就通过两段多次来回将这个新增订单记录复制到其他9台上。

晕倒,说了这么多,希望对你有帮助。ACID的C和CAP的C两者是横坐标和纵坐标的区别,2PC属于ACID的C范畴,Paxos属于CAP的C范畴。

以上仅供参考,可能有误。


事务保证强一致性。

我的意思是:

1)银行转账这个例子,这种强一致性,属于业务上的不同数据之间的强一致性。有转入就必须有转出。但由于网络原因,我们无法绝对保证有转入必定有转出。除非牺牲系统可用性,即不让用户看到处于中间状态的数据。我们只能做到最终一致性;

2)而数据副本之间的同步,只要R+W > N,那我们是可以轻松对多个副本实现强一致性;因为有R+W>N这个理论来支撑;

所以,我才说,分布式环境下,没有像银行转账那种业务数据之间的强一致性;但可以实现数据副本之间的强一致性;

而对用户而言,一般人认为的强一致性,就是银行转账那种强一致性,即我钱转出去了,要是没转进对方账户,那他是很担心的。为什么数据会不一致,是不是系统有问题?钱会不会丢了?
而数据副本之间的一致性,用户根本不关心,那是实现系统的人才需要关心的问题。

不知道我表达的是否清楚。
[该贴被tangxuehua于2015-02-14 20:42修改过]

2015-02-14 20:37 "@tangxuehua"的内容
而对用户而言,一般人认为的强一致性,就是银行转账那种强一致性,即我钱转出去了,要是没转进对方账户,那他是很担心的。为什么数据会不一致,是不是系统有问题?钱会不会丢了?
而数据副本之间的一致性,用户根本不关心,那是实现系统的人才需要关心的问题 ...

你说得很对,为了避免混淆,我们最好再明确一下:
第一种(事务/ACID)是业务一致性;
第二中(CAP的C)是数据一致性。

两者虽然都是使用一致性,一致性的领域完全不同,因此意义完全不同,相当于一个是业务;一个是技术,完全不同,那么为什么都用一致性这个词语,因为背后逻辑,无论业务或技术都必须遵循逻辑。

有时为了强调逻辑,前者称为业务逻辑的一致性;后者称为数据算法的一致性;

DDD等分析设计方法都根据逻辑一致性建模;所以,我们可以使用EventSourcing来实现逻辑一致性,再配合数据一致性,从而在分布式环境可替代2PC等。。。这涉及其他话题,如需要讨论可另外开新帖。

如此这样归类以后,我们解决问题的思路就拓展了。

参考文章:
线性化与串行化比较
使用Apache Samza对数据库进行彻底的"调教"
[该贴被banq于2015-03-09 16:02修改过]

那现在银行的数据库用到分布式了吗?他们是怎么解决强一致性的呢? 2PC ?
[该贴被lostalien于2016-04-17 12:40修改过]

2016-04-17 12:39 "@lostalien"的内容
那现在银行的数据库用到分布式了吗?他们是怎么解决强一致性的呢 ...

银行业务比较重视强一致性,银行核心业务很少使用真正具有横向扩展的分布式,基本是大型机中型机等纵向扩展的集中式计算。

解决强一致性一般使用关系数据库或使用EJB/Spring,EJB和Spring中JTA机制是2PC的一种实现,其XA事务实现2PC:
https://dzone.com/articles/xa-transactions-2-phase-commit

我注意到你的问题中可能将2PC的强一致性和分布式的强一致性混淆在一起。因为你的问题开始让人困惑,银行不使用分布式就没有办法解决强一致性了?使用2PC解决?其实2PC的分布式概念和我们通常谈论CAP定理下分布式系统是两种概念,正如关系数据库和NoSQL是两种概念一样。

首先,我们需要明白,2PC实现的高一致性与分布式的高一致性其实不是同一个意思,2PC或ACID的一致性是业务逻辑的精确性正确性的解决方案,而分布式中一致性是数据复制的精确性和正确性的解决方案。

比如一个操作涉及三个数据库的三个表a b c,如何保证这三个表的数据同时操作完成,保证在同一逻辑下的一致性,这是2PC关注所在,如果没有2PC,有可能a表修改成功,b表和c表没有修改成功,那么就出现不一致性。

以转账案例为说明,A账户转到B账户100元,A账户余额应该减去100元,而B帐号增加100元,如果A账户在上海机房服务器,B帐号在北京机房,那么通过2PC保证这种加减一致性,如果没有2PC,A帐号已经减去100元,但是B账户却没有增加100元,整个操作也没有报错回滚,所以,2PC是保证业务逻辑正确性,精确性的。

而分布式中一致性模型是系统中事件的历史集合,也就是Event事件流集合,保证分布式各个节点服务器按照这种历史事件正确改变它们的状态,比如上海机房的A账户余额减去100元,那么北京机房的A账户如何保证也是减去100元?因为A账户是分布在上海 北京几个地方的,那么我们将A账户减去100元这个动作包装成事件,发送消息到其他节点服务器,这样北京机房接受到这个消息后,会自动执行这个事件,将北京服务器内的A账户减去100元;同样,B账户增加100元,如果其他地方也存在B账户,那么也是通过分布式一致性模型来同步状态,这种算法称为共识一致性算法,比如Paxos算法。

由此可见,2PC的一致性和分布式的一致性是不同的,虽然2PC也涉及到分布式,但是这种分布式和我们通常基于CAP定理下的分布式是不同含义。所以,EJB或Spring可以不用实现具有充分横向扩展的分布式系统基础上使用2PC实现逻辑正确的强一致性。

参考:
分布式系统指南大纲

[该贴被banq于2016-04-17 20:01修改过]

好的我理解一下