设计数据密集型应用

《设计数据密集型应用》第七章(6) 事务:串行化(1)

2019-05-04  本文已影响0人  MeazZa

之前我们介绍了几种弱隔离性的概念和实现方式,本节我们继续讨论强隔离性保证:串行化。它保证了即使事务是以并行方式执行的,但结果和串行执行是一致的,也就是这种隔离性的保证可以避免所有可能的竞争状态。下面我们会分别介绍几种串行化的实现方式,以及它们各自的性能表现等。

真正的串行执行

最简单的实现方式是:使用一个线程,同一时间只执行一个事务。这种方式在很早就被提出,但最近被真正采用的原因主要有以下两个:

使用单一线程处理所有事务,可能避免使用锁,它的瓶颈在只有单一CPU核工作,因此事务的结构需要进行针对性的调整。

在存储过程中封装事务

数据库事务设计的意图,是能够封装用户行为的全部流程。比如,预定一张航空机票的行为包括:查找路线和票价、可选的座位,确定行程,预定行程中每次飞行的座位,输入乘客信息,支付。数据库的设计者希望所有的行为在一次提交中完成,以保证原子性等。

但由于事务的过程需要人类的输入,如果每个事务都等待用户输入的话,数据库需要支持大量的并发事务,并且大部分是空闲的。因此,大部分数据库并不采用这种方式,而采用OLTP的方式,缩短事务的保持时间,一个HTTP请求就等于一个事务。

采用这种交互式风格的事务,在应用程序和数据库之间,请求和查询结果会反复进行网络传输。并且如果我们不允许事务并发处理,数据库需要等待应用程序提交下一次查询,造成吞吐量的大幅下降。

为了解决这个问题,数据库提出了存储过程(stored precedure)的概念,应用程序将所有的数据库操作封装在存储过程中,并且编译后存储在数据库中,应用程序通过传递参数使用该存储过程,完成事务的处理,这里并不需要任何和网络和磁盘I/O。交互式事务和存储过程的区别如下图所示:

交互式事务和存储过程
存储过程的优缺点

存储过程在一些数据库中实现,并且已经成为SQL-1999标准的一部分,但它是有一些缺点的:

不过存储过程也在改进中,比如对通用编程语言的支持:VoltDB支持Java或者Groovy,Datomic支持Java或者Clojure,Redis支持Lua。

分区

为了能够提高串行化的CPU利用率,从而提高事务的处理效率,可以将数据进行分区。可以为每个分区分配一个CPU核,如果这个分区的读写操作不影响其他分区的话,是可以在单独执行该事务的。

如果是跨分区的事务,仍然需要是全局串行的。因此对于单纯的key-value型的数据库来说,分区是比较简单的,但如果是包括多个二级索引的话,就需要很多跨分区的协调了。

小结

串行化执行事务有以下的一些特点:

上一篇下一篇

猜你喜欢

热点阅读