让咱们用最经典的 Use Case:“A账号向B账号汇钱”来讲明一下,熟悉RDBMS事务的都知道从账号A到账号B须要6个操做:html
从A账号中把余额读出来; 对A账号作减法操做; 把结果写回A账号中; 从B账号中把余额读出来; 对B账号作加法操做; 把结果写回B账号中;
为了数据的一致性,这6件事,要么都成功作完,要么都不成功,并且这个操做的过程当中,对A、B账号的其它访问必需锁死,所谓锁死就是要排除其它的读写操做,否则会有脏数据的问题,这就是事务。node
若是A账号和B账号的数据不在同一台服务器上怎么办?咱们须要一个跨机器的事务处理。也就是说,若是A的扣钱成功了,但B的加钱不成功,咱们还要把A的操做给回滚回去。这在跨机器的状况下,就变得比较复杂了。mysql
若是不考虑性能的话,保证事务并不困难,系统慢一点就好了;除了考虑性能外,咱们还要考虑可用性,也就是说,一台机器没了,数据不丢失,服务可由别的机器继续提供。 因而,咱们须要重点考虑下面的这么几个状况:算法
要解决数据不丢,只能经过数据冗余的方法,就算是数据分区,每一个区也须要进行数据冗余处理。这就是数据副本:当出现某个节点的数据丢失时能够从副本读到,数据副本是分布式系统解决数据丢失异常的惟一手段。因此在数据冗余状况下考虑数据的一致性和性能的问题:sql
1)要想让数据有高可用性,就得写多份数据。数据库
2)写多份的问题会致使数据一致性的问题。服务器
3)数据一致性的问题又会引起性能问题网络
这就是软件开发,按下了葫芦起了瓢。并发
数据一致性能够简单分为三类:异步
弱一致性(weak),当你写入一个新值后,读操做在数据副本上可能读出来,也可能读不出来 强一致性(strong),新的数据一旦写入,在任意副本任意时刻都能读到新值 最终一致性(eventually),当你写入一个新值后,有可能读不出来,但在某个时间窗口以后保证最终能读出来
在分布式系统中,每一个节点虽然能够知晓本身的操做时成功或者失败,却没法知道其余节点的操做的成功或失败。当一个事务跨越多个节点时,引入一个做为协调者(coordinator)的组件来统一掌控全部节点(称做参与者)的操做结果,并最终指示这些节点是否要把操做结果进行真正的提交(好比将更新后的数据写入磁盘等等)。
两阶段提交(two phase commit, 2PC)的算法以下:
第一阶段(vote):
第二阶段(commit):
2PC实现了强一致性,其最大缺点就是它经过阻塞完成,会极大影响性能;另外一个问题则在timeout上:
3PC是把二段提交的第一个段break成了两段:询问,而后再锁资源。最后真正提交。其核心理念是:在询问的时候并不锁定资源,除非全部人都赞成了,才开始锁资源。
理论上来讲,若是第一阶段全部的结点返回成功,那么有理由相信成功提交的几率很大。这样一来,能够下降参与者Cohorts的状态未知的几率。也就是说,一旦参与者收到了PreCommit,意味他知道你们其实都赞成修改了。这一点很重要。下面咱们来看一下3PC的状态迁移图:(注意图中的虚线,那些F,T是Failuer或Timeout,其中的:状态含义是 q – Query,a – Abort,w – Wait,p – PreCommit,c – Commit)
从上图的状态变化图咱们能够从虚线(那些F,T是Failuer或Timeout)看到——若是结点处在P状态(PreCommit)的时候发生了F/T的问题,三段提交比两段提交的好处是,三段提交能够继续直接把状态变成C状态(Commit),而两段提交则不知所措。
Paxos是一种民主选举的算法,目的是让整个集群对某个值的变动达成一致,大多数节点的决定会成个整个集群的决定。任何一个点均可以提出要修改某个数据的提案,是否经过这个提案取决于这个集群中是否有超过半数的结点赞成(须要集群中的节点是单数)。
这个算法有两个阶段(假设这个有三个结点:A,B,C):
第一阶段:Prepare阶段
A把申请修改的请求Prepare Request发给全部的结点A,B,C。注意,Paxos算法会有一个Sequence Number(提案号,这个数不断递增,并且是惟一的,也就是说A和B不可能有相同的提案号),这个提案号会和修改请求一同发出,任何结点在“Prepare阶段”时都会拒绝其值小于当前提案号的请求。因此,结点A在向全部结点申请修改请求的时候,须要带一个提案号,越新的提案,这个提案号就越是是最大的。
若是接收结点收到的提案号n大于其它结点发过来的提案号,这个结点会回应Yes(本结点上最新的被批准提案号),并保证不接收其它<n的提案。这样一来,结点上在Prepare阶段里老是会对最新的提案作承诺。
优化:在上述 prepare 过程当中,若是任何一个结点发现存在一个更高编号的提案,则须要通知 提案人,提醒其中断此次提案。
第二阶段:Accept阶段
若是提案者A收到了超过半数的结点返回的Yes,而后他就会向全部的结点发布Accept Request(一样,须要带上提案号n),若是没有超过半数的话,那就返回失败。
当结点们收到了Accept Request后,若是对于接收的结点来讲,n是最大的了,那么,它就会修改这个值,若是发现本身有一个更大的提案号,那么,结点就会拒绝修改。
咱们能够看以,这彷佛就是一个“两段提交”的优化。其实,2PC/3PC都是分布式一致性算法的残次版本,Google Chubby的做者Mike Burrows说过这个世界上只有一种一致性算法,那就是Paxos,其它的算法都是残次品。
CAP理论为:一个分布式系统最多只能同时知足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。
对于多数大型互联网应用的场景,主机众多、部署分散,并且如今的集群规模愈来愈大,因此节点故障、网络故障是常态,并且要保证服务可用性达到N个9,即保证P和A,舍弃C(退而求其次保证最终一致性)。虽然某些地方会影响客户体验,但没达到形成用户流程的严重程度。
但对于银行等金融机构,C必须保证。网络发生故障宁肯中止服务,这是保证CA,舍弃P。
数据库事务(Transaction)是指做为单个逻辑工做单元执行的一系列操做,要么彻底地执行,要么彻底地不执行。
一方面,当多个应用程序并发访问数据库时,事务能够在应用程序间提供一个隔离方法,防止互相干扰。另外一方面,事务为数据库操做序列提供了一个从失败恢复正常的方法。
事物有下面4个特性:
实际工做中事务几乎都是并发的,彻底作到互相之间不干扰会严重牺牲性能,为了平衡隔离型和性能,SQL92规范定义了四个事务隔离级别:
事务隔离级别越高,越能保证数据的一致性,但对并发性能影响越大,一致性和高性能必须有所取舍或折中。
通常状况下,多数应用程序能够选择将数据库的隔离级别设置为读已提交,这样能够避免脏读,也能够获得不错的并发性能。尽管这个隔离级别会致使不可重复度、幻读,但这种个别场合应用程序能够经过主动加锁进行并发控制。
BASE理论是对CAP理论的延伸,核心思想是即便没法作到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用能够采用适合的方式达到最终一致性(Eventual Consitency)。
BASE支持的是大型分布式系统,提出经过牺牲强一致性得到高可用性。