MongoDB的锁机制

在MongoDB里面有如下4中锁:


描述

S

读操作的共享锁

IS

意向读操作共享锁

X

排它的写锁

IX

意向的排它写锁

MongoDB 锁的兼容矩阵:

IS

IX

S

X

IS

yes

yes

yes

no

IX

yes

yes

no

no

S

yes

no

yes

no

X

no

no

no

no

MongoDB使用多粒度锁来锁定资源, 它允许我们按照全局的, 库级的或者集合级的方式锁定资源。MongoDB使用读写锁来允许对一个共享的资源并发的进行读, 比如一个库或者集合。除了一个共享模式读锁(S)和一个排它锁(X), 意向读锁(IS)和意向写锁(IX)表明对一个资源使用一种更细力度的读或者写。

当要在某个粒度锁定, 所有更高级的锁定都使用意向锁, 比如, 当要锁定某个集合来写操作(使用X模式),相应的数据库锁和全局所必须以意向排它锁(IX)模式锁定。一个单一的数据库可以同步的被IS和IX模式锁定, 但是一个X锁不能与其他任意的锁同时存在, 并且一个S锁只可以和IS锁同时存在。所有的锁是公平的, 读锁和写锁按照顺序加入队列, 然而, 为了优化吞吐量, 当一个请求被处理,所有的兼容的请求会被同时处理。比如, 考虑一种情况, 一个X锁刚刚被释放, 并且此时的冲突队列包含如下的items: IS->IS->X->S->IS.

在严格的先进先出(FIFO)顺序下, 只有前2个IS会被执行, 相反, MongoDB会执行所有的IS和S模式, 一旦它们都被处理完, 它会执行X, 即便此时在请求队列里面加入了新的IS或者S, 因为所有其他的请求会放到队列的头部, 以确保没有任何情况会一直无发执行。

锁机制的代码实现

在MongoDB的意向锁机制是通过LockManager来实现的, 在该类里面主要提供了unlock和unlock两个接口, 来对树形层次的结构来加入意向锁。获取锁的流程如下:

MONGOdb文档锁 mongodb锁机制_读锁


从上面的图可知, 枷锁的过程如下:

  • 根据锁的模式, 如果是意向锁就先找到对应的partition;
  • 经过resourceId映射到相应的PartitionLockHead,
  • 如果找不到, 就经过resourceID映射到一个bucket, 在该bucket里面, 通过resourceId找到LockHead;
  • 在每一个LockHead里面, 保存了grantList和conflictList, grantedModes和conflictModes分别代表了grant和conflict对于每一种模式的锁机制还不是在其队列里面, 如果对应的位是0, 表示没有还模式的锁请求, 否则就是有。在conflictCounts数组里面, 分别代表每一种锁模式的请求队列个数;
  • 如果要找的所模式存在, 就讲conflictCounts[mode]++;
  • 如果不存在, 就创建该锁模式的lockRequest, 并加入到conflictList或者grantList;

MVCC的实现

MVCC(multi-version concurrent control)是并发控制的一种方式, 上面讨论的加锁的方式, 虽然可以提升可兼容的并发性能, 但是, 毕竟像数据库这样的场景, 有很多的并发读写操作。
多版本并发控制(MVCC)是提升读的一种常用的方式, 它能够在读的时候不用加锁操作, 在读多写少的场景下非常的适合。

乐观锁

乐观锁是说,每次去获取数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。