mongodb的MMAPV1存储引擎锁的最小粒度为Collection级别,包括读锁(S)、写锁(X),并且还提供了意向读锁(IS)、意向写锁(IX),意向锁会加在比读写锁更高的粒度上,比如在Collection上加了读锁,相应的会在db、global加意向读锁。
意向锁并不是真正的锁,只是表达了加锁的意向,所以意向锁之间是互相兼容的。X锁和任何锁都是互斥的,包括IX锁,比如当前要更新Collection中的一个document,使得该Collection被加了X锁,IX锁会自动加载Collection所在db、global上,此时如果要在db级别做更新操作就需要在db上加X锁,由于db上已经有了IX锁,所以db级别的更新操作被阻塞。
意向锁的意义在于让更大级别的更新操作可以立即看到是否有小级别的更新操作在进行(如果没有意向锁,大更新操作要判断是否有小更新操作在进行,就需要遍历整个表),如果有,则大操作需要等待小操作释放锁(从而释放意向锁),如果没有,则可以放心的进行大操作。
S、X锁兼容性矩阵
S X S + - X - -
+:兼容 ; -:不兼容
S、X、IS、IX锁兼容性矩阵
IS IX S X IS + + + - IX + + - - S + - + - X - - - -
+:兼容; -:不兼容
锁优先级
如果在一个Collection上有多个读写操作时,就会有优先级策略的问题,比如当前Collection上的X锁刚刚释放,此时的冲突队列如下
IS → IS → X → X → S → IS
如果是严格FIFO,则只有前两个IS锁可以被授权,但mongodb会授权队列中所有的IS、S锁,即便是此时新入队的IS、S锁,当IS、S锁释放后才会授权后面的X锁。这点与mysql不同,经测试mysql是严格的FIFO。
mongodb并不支持事务,即mongodb无法保证多个操作的原子性,比如先find后update,但其通过锁机制可以保证每一个操作的原子性,比如findAndUpdate。
参考:https://docs.mongodb.com/manual/faq/concurrency/