分布式事务?咱先弄明白本地事务再说 - 可用性和速度(锁和并发)的博弈

 

在上文《分布式事务?咱先弄明白本地事务再说 - ACID》中,咱们讲解了数据库的事务及事务的特性ACID,了解到一个数据库要支持事务,就须要实现完备的事务的规范,咱们才能说这是一个支持事务的数据库,例如Mysql、Oracle等。
本文就来讨论一下数据库实现事务的几个关键阶段,背后都经历了哪些曲折的技术变迁。html

数据库的事务,本质上是解决数据库并发的问题,处理多个数据操做时相互不干扰,都能获得正确的执行结果,这个问题在应用层是没法解决的,由于你彻底不知道同时可能有另外一个程序(进程)也在操做相同的数据项,因此,这个问题必须由数据库来解决。sql

彻底顺序执行

最简单的思路,就是彻底顺序执行全部的数据库操做,不须要加锁,简单的说就是全局排队,序列化进行全部的事务单元,数据库同时只处理一个事务,特色是强一致性,处理性能低。
这种模式适应于早期的C/S开发模式,单机系统,一个系统,一个数据库(例如Access数据库),彻底本地用户+本地系统+本地事务。数据库

 

 

 

 

并行+排他锁

开始支持并行处理事务,若是事务之间涉及到相同的数据项时,会使用排他锁,或叫互斥锁,先进入的事务独占数据项之后,其余事务被阻塞,等待前面的事务释放锁。并发

 

 

 

注意,在整个事务1结束以前,锁是不会被释放的,因此,事务2必须等到事务1结束以后开始。分布式

并行+读写锁

采用了 并行+排他锁 之后,大幅提高了数据库事务处理效率,若是几个事务之间没有共享数据项,彻底能够并行被处理,但,一些数据库大牛们显然对这个性能还不知足,进一步研究细化发现,全部的事务当中,对数据的操做无非是读和写排列组合的几种结果, 读读、写写、读写、写读 这4种状况的不断重复。性能

哪些操做之间能够相互兼容,或者共享呢?例如,读的时候为何要阻止读呢?优化

因此,读写锁就应用而生了,进一步细化锁的颗粒度,区分读和写,让读和读之间不加锁,这样下面的俩个事务就能够同时被执行了。版本控制

 

 

 

读写锁,可让读和读并行,而读和写、写和读、写和写这几种之间仍是要加排他锁。code

MVCC

有人可能要说,优化到这个份上,已经差很少了吧,还有空间?
大牛们用行动告诉世人,答案是确定的。
每每,肯定一个模型不是最难的,难的是对这个模型实现的境界,大牛们会把本身的实现往死里优化,并行+读写锁 解决了读和读的并行,大牛们接下来要解决的是写和读、读和写,甚至写和写是否均可以并行!htm

这个技术就是如今大部分数据库在使用的事务处理技术,MVCC(Multi Version Concurrency Control),也就是Copy on Write的思想,对数据项进行多版本控制,一个精妙的想法,用空间换时间,进一步优化锁,减小锁。

 

 

MVCC

给每条记录增长版本号和删除俩个字段,在事务开始的时候copy一个新的版本,此时事务操做的其实是一个副本,所以不会影响其余事务对此数据项的读操做,选择版本号最大的记录读取。

MVCC的好处,

  1. 除了支持读和读并行意外,可用让读和写并行、写和读并行,但,为了保证一致性,写和写是没法并行的。
  2. 大事务支持较好,以前的全部方案,由于锁的广泛存在,若是一个事务执行的时间太长,意味着后面的事务要长期等待,甚至超时,因此在以前,数据库一直建议不要维持大的数据库事务。

另外,MVCC支持读已提交 和 重复读俩种隔离级别,串行和读未提交都没有意义,一个必需要求排队执行,另外一个要求必须读取最新数据。

小结

人类对速度的激情是没有最快,只有更快。
因此,以上方案的演变,本质是速度上的逐步提高的过程,到目前MVCC为止,在数据库层面能作的事情已经很少了。

进一步,如何解决写和写冲突的问题,这里提供俩个思路

  1. 乐观锁,适合于资源争抢不太严重的场景,由业务层控制,增长一个字段记录读取时的状态,更新是判断是否与读取时的状态一致,决定是否进行写操做,避免发生写操做冲突;
  2. BASE理论(Basically Available[基本可用],Soft State[软状态]和Eventually Consistent[最终一致]),数据库彻底放开一致性要求,出现冲突,由用户决定,相似于Git Merge合并冲突的解决机制,咱们后面单独撰文解读。
相关文章
相关标签/搜索