InnoDB死锁分析-锁基础理论


死锁是由加锁引起的,要解决死锁首先要明白为什么加锁、加什么样的锁。本篇主要讨论锁相关的一些基础理论以及InnoDB的MVCC特性。

锁的基础理论

为什么加锁

数据库与其它涉及并发的程序一样,都要处理并发的两个关键点互斥协作;锁就是为了保证互斥特性,让多用户请求可以一致性的读取和修改数据。如果不通过加锁来控制访问的一致性则会造成脏读、幻读、不可重复读等问题。

锁模式

锁就是为了保证某个资源被按照合理的顺序被访问。如果使用一个简单的互斥锁来保护资源,那么当多个读取者访问资源并且期间没有其它的写入者访问,那么每个读取者依旧要依次获取锁资源,但是最终每个读取者获取的还是同一个结果。这样就限制了系统的并发性能,毕竟我们使用锁的原因是希望通过并发来提高系统性能同时依靠锁来解决并发引起的问题

如果我们为读写者提供不同的锁,对于被读取者的锁保护的资源允许其它的读取者再加上一把锁并且限制其它的写入者加锁;这样我们就能保证了上述情况下所有的读取者最终获取的结果与之前相同。这样即可以保证系统的安全又可以保证并发的性能,这就是锁模式的一个维度的表现。通常情况下我们将这种锁根据其特性不同分别命名为共享锁 S排它锁 X

如上所述,不同的锁之间有的能“叠加”有的则是互斥的,这就是锁的兼容性

  S X
S 兼容 不兼容
X 不兼容 不兼容

众所周知加锁操作需要有构建锁对象,维护锁对象关系等一系列操作,这都会消耗系统性能。假如一个操作者访问某个资源对它进行了加锁操作,但是在它整个操作过程都没有其它人来访问这个资源;如此这个加锁操作的资源消耗就白白浪费了也等于限制了系统的并发性能。那么如果我们在加锁的时候不真正的执行加锁动作,而是在那里贴一个小纸条标示有人来过并且要加锁。这样如果没有其它人来访问此资源则依旧安全并且避免了加锁消耗;如果有人来访问资源其看到这个意向小纸条则为先进去那个人完成加锁操作并且将自己添加到这个锁等待之中,如此依旧保证了系统的安全。这就是锁模式的另外一个维度意向锁

综上所述,我们将锁按照不同的模式分为S X两种,同时这两种锁又可以依靠意向标识来表示则为IS IX锁总共4种不同的锁,这就是Multiple granularity locking

InnoDB存储引擎支持意向锁设计比较简练;众所周知InnoDB支持行级锁,其意向锁用于表级锁,设计目的主要是为了揭示行级锁的类型。InnoDB支持IS和IX锁两种意向锁:

  1. IX表示事务想要获得一张表中某几行的排他锁
  2. IS表示事务想要获得一张表中某几行的共享锁
  IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容

锁粒度

比如系统的资源是一家里面有很多房子的宾馆,一种加锁方式是当有人入住以后将整个宾馆锁起来,另外一种方式就是锁住入住的房子,这就是锁粒度的划分。

InnoDB支持行级锁,一般认为行级锁会消耗更多资源,但是实际上InnoDB的实现不需要锁升级,其依赖bitmap实现所以一个锁和多个锁的开销是相同的。

lock与latch

最后再讨论一下一个容易混淆的概念lock与latch。

latch一般称之为闩锁是一种轻量级的锁,latch又可以分为mutex(互斥量)和rwlock(读写锁)。其主要的目的是保证并发线程操作临界资源的正确性。这种锁没有死锁检测机制,所以这里发生了死锁不能被检测出来并恢复处理。 lock的对象是事务,用于锁定的是数据库中的对象,比如表、页、行。根据二阶段加锁协议此类lock对象仅仅在commit和rollback后才进行释放。这里是有死锁检测机制的,InnoDB采用Wait-For-Graph算法来实现死锁检测的。 img

InnoDB存储引擎中的Latch可以通过SHOW ENGINE INNODB MUTEX来查看

mysql> SHOW ENGINE INNODB MUTEX;
+--------+-------------------+-------------+
| Type   | Name              | Status      |
+--------+-------------------+-------------+
| InnoDB | dict0dict.cc:1057 | os_waits=2  |
| InnoDB | log0log.cc:844    | os_waits=1  |
| InnoDB | fil0fil.cc:1690   | os_waits=1  |
| InnoDB | dict0dict.cc:1066 | os_waits=3  |
| InnoDB | log0log.cc:907    | os_waits=11 |
+--------+-------------------+-------------+
5 rows in set (4.14 sec)

在Debug模式下SHOW ENGINE INNODB MUTEX能显示更多的信息 img

各个字段的描述如下 img

相对于latch来看,lock信息就显得直观了。可以通过SHOW ENGINE INNODB STATUS 及information_schema架构下的INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS来观察锁的信息 。

本文采用CC BY-SA许可发布,您可以自由的转载分享。

转载请保留出处 BeanMr.
http://blog.beanmr.com/2016/07/13/innodb-lock/