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

banq 15-01-02
                   

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修改过]

                   

7
tangxuehua
2015-02-12 20:25

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

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

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

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

banq
2015-02-12 21:21

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

“银行转账:有转出必定要有转入,要么全部成功,要么全部不成功。”这个属于事务,只能使用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范畴。

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


tangxuehua
2015-02-14 20:37

事务保证强一致性。

我的意思是:

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

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

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

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

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

banq
2015-02-15 07:52

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


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

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

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

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

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

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

2Go 1 2 下一页