MySQL 架构 - 并发控制
2009-06-03 11:18:49 来源:WEB开发网并发控制
可能会出现同时修改同一数据的情况发生。这就涉及到了并发控制问题。MySQL通过两个级别解决这个问题。服务器级别和存储引擎级别。并发控制在理论上来说都是一个庞大的话题。这不是本书的关注点。我们所讲到的是一个MySQL处理并发读和并发写的一个简单的介绍。
我们会用一个Unix系统下的EMAIL邮箱做为例子。经典的邮箱文件格式是很简单的。一个邮箱的所有信息都是一个接着一个连接起来的。这非常容易读取和解析mail的信息。邮件的分发也很简单。只要把信息添加到文件的内容的最后就可以了。
但是如果出现两个操作同时对一个邮箱进行分发操作会怎样?答案是肯定的,信息格式必然被破坏,两条混乱的信息插入到文件的最后。还好邮件分发程序用锁机制解决了这个问题。如果第二个消息要添加,就会遇到文件被锁。它必须要获得锁,才能分发这个信息。
读取锁和写入锁
从邮箱读取并不能引发什么错误。因为这些操作没有做任何的修改。如果删除操作和读邮箱操作同时进行的时候,会怎样呢?视情况而定,但是可能会读取一个毁坏的不连贯的信息。因此,为了安全,读取邮箱也要格外的小心。
如果把邮箱看做数据库的表,每条信息看做一行。就会发现这两种情况下错误是一样的。在很多情况下,一个邮箱就是简单的一张表。修改表的行和修改邮箱的信息是非常相似的。
对于这种经典的错误,解决方案也很简单。一般都是实现了两种锁。这两种锁一般叫做共享锁(shared locks)以及排它锁(exclusive locks)或者可以叫做读取锁(read locks)和写入锁(write locks)。
没必要担心锁的技术。我们会描述这个概念的。读取锁的资源是共享的,它们之间是非阻塞的。许多Clients同时读取同一数据,彼此之间并不会影响。写入锁,意思就是一种独占的意思。如,它们阻塞了读取锁和其他的写入锁。因为在同一时间只能有一个Client写入资源。避免在写的同时,数据被读取。
在数据库中,总会有锁的现象发生。MySQL会避免一个Client读取的同时,另一个进行修改。一般锁都是通过某种方式内部管理的,这种方式大多数时候是透明的。
锁的颗粒度
大部分都选择锁的对象这个方法来提高共享资源的并发性。要锁定你要更改的数据,而不是锁定整个资源。最佳的情况下,是锁定准确的数据。要尽可能的缩小锁定数据的范围。
锁的问题就是资源消耗。每个锁的操作,如得到一个锁,检查这个锁是否空闲,释放锁等等。额外的开销挺大。如果系统花费大量的时间来管理锁,而不是用来存储和获取数据,那么性能是很糟糕的。
锁策略一般是在锁的额外开销和安全性取一个折中的方法。这个策略会影响到性能。大部分商业的数据库不会给你更多的选择:你获得是行级别的锁。有大量的复杂的算法使得其具有很高的性能。
MySQL提供了更多的选择。它的存储引擎提供了自己的锁策略和锁的颗粒度。锁管理在存储引擎的设计中是非常重要的。
锁的颗粒度在某一级别,对于某些的操作有很大的性能提升。然而可能对于其他的引擎就不太适合了。因为MySQL本身提供了多个存储引擎。所以不会有一个通用的解决方案。让我们来看下比较重要的两个锁的策略。
表锁
在MySQL中,这是最基本的锁的策略了。消耗资源最少的就是表锁了。表锁和上面所描述的邮箱锁是相似的,它是把整个表进行锁定。当一个Client要操作表(Insert,delete,update等)。它获得了一个写锁。这样其他Client就不能操作这个表了。当没有Client执行写的操作。读取操作会得到一个读取锁。它并不会和其他的读取锁相冲突。
表锁的许多变化在特定的条件下有很好的性能。举个例子,READ LOCAL 表锁允许一些类型的写入操作并发执行。写入锁得优先级高于读取锁。因此一个请求的写入锁在队列中必会超过读取锁。(写入锁在队列中会超过读取锁,但是读取锁不会超过写入锁)。
虽然存储引擎能管理自己的锁,但是MySQL本身也使用了不同的表锁来提高效率。示例, 服务器对于ALTER TABLE这个语句使用了表锁。而不管存储引擎的锁管理。
行锁
这种锁可以带来最好的并发性,但是对资源的消耗也是最大的。行锁这种策略是非常熟悉的。在InnoDB和Falcon存储引擎
中可以使用行锁。行锁是存储引擎实现的。并不是服务器实现。服务器完全不知道存储引擎锁的实现。在以后的教程中会知道存储引擎有自己实现锁的方式。
更多精彩
赞助商链接