MongoDB 使用的是 “readers-writer” 锁, 可以支持并发但有很大的局限性。当一个读锁存在,许多读操作可以使用这把锁,然而, 当一个写锁的存在,一个单一的写操作会 ”exclusively“ 持有该锁,同一时间其它写操作不能使用共享这个锁。
举个例子,假设一个集合里有 10 个文档,多个 update 操作不能并发在这个集合上,即使是更新不同的文档。
在 2.2 版本以前,mongod 只有全局锁(锁定一个 server)。
从 2.2 版本开始,大部分读写操作只锁一个库(database),相对之前版本,这个粒度已经下降,例如如果一个 mongod 实例上有 5 个库,如果只对一个库中的一个集合执行写操作,那么在写操作过程中,这个库被锁;而其它 5 个库不影响。相比 RDBMS 来说,这个粒度已经算很大了!
MongoDB 3.4 版本,写操作的锁定粒度在表中数据记录(document)级别,即使操作对象可能是多条数据,每条数据在被写入时都会被锁定,防止其他进程写入;但是写操作是非事务性的,即写入多条数据,即使当前写入操作还没有完成,前面已经写入的数据也可以被其他进程修改。除非指定了 $isolated,一次写入操作影响的数据无法在本次操作结束之前被其他进程修改。
isolated 也是非事务性的,即如果写入过程出错,已经完成的写入操作不会被 rollback;另外,isolated 需要额外的锁,无法用于 sharded 方式部署的集群。
db.serverStatus() db.currentOp()
使用 serverStatus 或者使用 currentOp 都可以查看锁状态。
操作 | 锁定类型 |
---|---|
查询 | 读锁 |
通过cursor读取数据 | 读锁 |
插入数据 | 写锁 |
删除数据 | 写锁 |
修改数据 | 写锁 |
Map-reduce | 读写锁均有,除非指定为non-atomic,部分mapreduce任务可以同时执行(猜测是生成的中间表不冲突的情况下) |
添加index | 通过前台API添加index,锁定数据库一段时间 |
db.eval() | 写锁,同时阻塞其他运行在MongoDB上的JavaScript进程 |
eval | 写锁,如果设定锁定选项是nolock,则不会有些锁,而且eval无法向数据库写入数据 |
aggregate() | 读锁 |
MongoDB 使用的是 “readers-writer” 锁, 可以支持并发但有很大的局限性。当一个读锁存在,许多读操作可以使用这把锁,然而, 当一个写锁的存在,一个单一的写操作会 ”exclusively“ 持有该锁,同一时间其它写操作不能使用共享这个锁。
举个例子,假设一个集合里有 10 个文档,多个 update 操作不能并发在这个集合上,即使是更新不同的文档。