MongoDB 并发机制

本文详细介绍了MongoDB从2.2到3.2版本的并发机制,包括锁类型、锁粒度、查看锁状态的方法,以及不同版本中并发控制的改进。MongoDB采用读者-写者锁,支持数据库级别的锁粒度,并通过锁的退让提高并发性能。随着版本升级,MongoDB在存储引擎如WiredTiger中引入了多版本并发控制和更细粒度的锁,以提升并发性能和数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


并发机制

以下列出各版本的新特性


MongoDB 2.2 并发机制

https://docs.mongodb.com/v2.2/faq/concurrency/

1、锁类型

使用 readers-writer 锁机制,允许同时有多个读操作,但只能有一个写操作;一个写操作会阻塞其它读、写操作;写操作优先级高于读操作

2、锁粒度

2.2 版本之前只有一个实例级别的全局锁。从 2.2 版本开始大多操作实现了数据库级别的锁粒度,少量操作仍用到实例级的全局锁

3、查看锁状态

i. db.serverStatus()

Locks:https://docs.mongodb.com/v2.2/reference/server-status/#server-status-locks

"locks" : {
        "." : {
                "timeLockedMicros" : {
                        "R" : <num>,
                        "W" : <num>
                },
                "timeAcquiringMicros" : {
                        "R" : <num>,
                        "W" : <num>
                }
        },
...
        "<database>" : {
                "timeLockedMicros" : {
                        "r" : <num>,
                        "w" : <num>
                },
                "timeAcquiringMicros" : {
                        "r" : <num>,
                        "w" : <num>
                }
        }
},

Global Lock:https://docs.mongodb.com/v2.2/reference/server-status/#server-status-global-lock

"globalLock" : {
        "totalTime" : <num>,
        "lockTime" : <num>,
        "currentQueue" : {
                "total" : <num>,
                "readers" : <num>,
                "writers" : <num>
        },
        "activeClients" : {
                "total" : <num>,
                "readers" : <num>,
                "writers" : <num>
        }
},
ii. db.currentOp()

Current Operation:https://docs.mongodb.com/v2.2/reference/current-op/

{
  "inprog": [
             {
                     "opid" : 3434473,
                     "active" : <boolean>,
                     "secs_running" : 0,
                     "op" : "<operation>",
                     "ns" : "<database>.<collection>",
                     "query" : {
                     },
                     "client" : "<host>:<outgoing>",
                     "desc" : "conn57683",
                     "threadId" : "0x7f04a637b700",
                     "connectionId" : 57683,
                     "locks" : {
                             "^" : "w",
                             "^local" : "W",
                             "^<database>" : "W"
                     },
                     "waitingForLock" : false,
                     "msg": "<string>"
                     "numYields" : 0,
                     "progress" : {
                             "done" : <number>,
                             "total" : <number>
                     }
                     "lockStats" : {
                             "timeLockedMicros" : {
                                     "R" : NumberLong(),
                                     "W" : NumberLong(),
                                     "r" : NumberLong(),
                                     "w" : NumberLong()
                             },
                             "timeAcquiringMicros" : {
                                     "R" : NumberLong(),
                                     "W" : NumberLong(),
                                     "r" : NumberLong(),
                                     "w" : NumberLong()
                             }
                     }
             },
            ]
}
iii. mongotop

–locks 参数:https://docs.mongodb.com/v2.2/reference/mongotop/#cmdoption–locks

# mongotop22 -h localhost:28022 --locks
connected to: localhost:28022

                            db       total        read       write      2016-09-20T04:05:12
                         local         0ms         0ms         0ms
                         admin         0ms         0ms         0ms
                             .         0ms         0ms         0ms

...
iv. mongostat and/or

locked db 字段:https://docs.mongodb.com/v2.2/reference/mongostat/#fields

# mongostat22 -h localhost:28022
connected to: localhost:28022
insert  query update delete getmore command flushes mapped  vsize    res faults  locked db idx miss %     qr|qw   ar|aw  netIn netOut  conn       time 
     0      0      0      0       0       1       0     0m   128m    28m      0 local:0.0%          0       0|0     0|0    62b     1k     1   12:08:07 
     0      0      0      0       0       1       0     0m   128m    28m      0 local:0.0%          0       0|0     0|0    62b     1k     1   12:08:08 
...
v. the MongoDB Management Service (MMS)

4、锁的退让(yield)

当出现需要等待慢速 IO 操作时,临时释放掉锁,等 IO 完成后再重新添加锁
目的是将长时间操作占用的大锁拆分为多个细粒度的小锁,不会一直占用锁
2.0 基于时间分片 yield
2.2 优化算法,基于磁盘访问预测:增加了内存数据跟踪,能够预测出要读取的数据是否在内存中

5、产生数据库锁的操作

OperationLock Type
Issue a queryRead lock
Get more data from a cursorRead lock
Insert dataWrite lock
Remove dataWrite lock
Update dataWrite lock
Map-reduceRead lock and write lock, unless operations are specified as non-atomic. Portions of map-reduce jobs can run concurrently.
Create an indexBuilding an index in the foreground, which is the default, locks the database for extended periods of time.
db.eval()Write lock. db.eval() blocks all other JavaScript processes.
evalWrite lock. If used with the nolock lock option, the eval option does not take a write lock and cannot write data to the database.
aggregate()Read lock

6、产生数据库锁的管理命令

i. 长期写锁

ii. 读锁
The db.collection.group() operation takes a read lock and does not allow any other threads to execute JavaScript while it is running.

iii.短期锁

7、同时锁多个库的操作

  • db.copyDatabase() must lock the entire mongod instance at once.
  • Journaling, which is an internal operation, locks all databases for short intervals. All databases share a single journal.
  • User authentication locks the admin database as well as the database the user is accessing.
  • All writes to a replica set’s primary lock both the database receiving the writes and the local database. The lock for the local database allows the mongod to write to the primary’s oplog.

8、分片

每个分片 mongod 相互独立,互不影响

9、主库

写数据同时写 local.oplog,要锁 2 个库

10、备库

备库上批量并行的执行 oplog,在同步数据时不允许读操作

11、JavaSript

一个 mongod 实例同时只能执行一个 JavaScript 操作

一些使用限制:

  • mapReduce
    The JavaScript operations within a mapReduce job are short lived and yield many times during the operation. Portions of the map-reduce operation take database locks for reading, writing data to a temporary collection and writing the final output of the write operation.
  • group
    The group takes a read lock in addition to blocking all other JavaScript execution.
  • db.eval()
    Unless you specify the nolock option, db.eval() takes a write lock in addition to blocking all JavaScript operations.
  • $where
    Only a single query that uses the $where operation can run at a time.

MongoDB 2.4 并发机制

https://docs.mongodb.com/v2.4/faq/concurrency/

1、查看锁状态

i. db.serverStatus()
支持指定输出的字段,如:

db.serverStatus( { repl: 0, indexCounters: 0, locks: 0 } )
db.serverStatus( { workingSet: 1, metrics: 0, locks: 0 } )

2、JavaScript

使用 V8 JavaScript 引擎,支持同时执行多个 JavaScript 操作


MongoDB 2.6 并发机制

https://docs.mongodb.com/v2.6/faq/concurrency/

1、锁的退让(yield)

扫描索引时不 yield lock

2、同时锁多个库的操作

  • User authentication requires a read lock on the admin database for deployments using 2.6 user credentials. For deployments using the 2.4 schema for user credentials, authentication locks the admin database as well as the database the user is accessing.
    用户认证:2.6 锁 admin 一个库,2.4 锁 admin 和 user auth 两个库

3、事务

不支持多文档之间事务
支持对单个文档的原子性操作
https://docs.mongodb.com/v2.6/core/write-operations-atomicity/

4、隔离

https://docs.mongodb.com/v2.6/faq/concurrency/#what-isolation-guarantees-does-mongodb-provide
并发读写操作情况下提供以下隔离保证:
1、单独文档的读写操作是原子性的,保证文档处于一致性的状态。意味着,读不会看到部分更新的文档;索引和集合内容保持一致性;对单一文档的读写是串行的
2、查询谓词的正确性。如 find、update 只会影响符合条件的文档
3、排序的正确性。find、aggregate 的排序顺序不受并发写的影响

多文档操作没有事务性保证,会出现以下情况:
1、Non-point-in-time read operations。同时执行 read 和 update,read 可以看到 update 后的数据,而不是查询那一刻的快照
2、Non-serializable operations。假如有一个读操作和一个写操作,t1 读 d1、t3 写 d1,如果操作是串行的,读操作必须在写操作前执行。再假如 t2 写 d2、t4 读 d2,这又导致写操作必选先于读操作。这就形成了循环依赖,所以读写两个操作不能串行执行
3、Dropped results。读操作过程中更新或删除文档,可能导致读取不到匹配的文档的情况

5、读未提交数据

读出未经客户端确认的写操作的数据
读出即将回滚的数据
上述场景也被称作 read uncommitted


MongoDB 3.0 并发机制

3.0 允许多个客户端同时读写

1、锁类型

支持多粒度锁,支持全局、数据库、集合级别
支持存储引擎实现自己的并发控制机制,可以实现小于集合级别的锁
除了共享锁(S)、排他锁(X),还增加了 IS、IX 意向锁。意向锁表示将用更细粒度的锁来读写资源。在某个粒度上添加锁,在所有更高级别上也要添加意向锁

参考:https://en.wikipedia.org/wiki/Multiple_granularity_locking

To GetMust Have on all Ancestors
IS or SIS or IX
IX, SIX or XIX or SIX

兼容性:

ModeNLISIXSSIXX
NLYesYesYesYesYesYes
ISYesYesYesYesYesNo
IXYesYesYesNoNoNo
SYesYesNoYesNoNo
SIXYesYesNoNoNoNo
XYesNoNoNoNoNo

读写锁是公平的,按顺序排队。为了提高吞吐量,当授权一个锁请求,同时也会授权其它所有兼容的锁请求。

2、锁粒度

WiredTiger

大部分读写操作使用乐观锁
只在全局、库、集合级别使用意向锁
一旦存储引擎发现两个操作存在冲突,会引发其中一个写冲突,让 MongoDB 重试该操作
一些全局操作,主要是跨库的短期操作,仍用到全局实例锁
一些操作,比如删除集合,仍用到排他的数据库锁

MMAPv1

3.0 开始使用集合级别的锁机制,之前版本是数据库锁

3、查看锁状态

i. db.currentOp()

{
  "inprog": [
       {
         "desc" : <string>,
         "threadId" : <string>,
         "connectionId" : <number>,
         "opid" : <number>,
         "active" : <boolean>,
         "secs_running" : <NumberLong()>,
         "microsecs_running" : <number>,
         "op" : <string>,
         "ns" : <string>,
         "query" : <document>,
         "insert" : <document>,
         "planSummary": <string>,
         "client" : <string>,
         "msg": <string>,
         "progress" : {
             "done" : <number>,
             "total" : <number>
         },
         "killPending" : <boolean>,
         "numYields" : <number>,
         "locks" : {
             "Global" : <string>,
             "MMAPV1Journal" : <string>,
             "Database" : <string>,
             "Collection" : <string>,
             "Metadata" : <string>,
             "oplog" : <string>
         },
         "waitingForLock" : <boolean>,
         "lockStats" : {
             "Global": {
                "acquireCount": {
                   "r": <NumberLong>,
                   "w": <NumberLong>,
                   "R": <NumberLong>,
                   "W": <NumberLong>
                },
                "acquireWaitCount": {
                   "r": <NumberLong>,
                   "w": <NumberLong>,
                   "R": <NumberLong>,
                   "W": <NumberLong>
                },
                "timeAcquiringMicros" : {
                   "r" : NumberLong(0),
                   "w" : NumberLong(0),
                   "R" : NumberLong(0),
                   "W" : NumberLong(0)
                },
                "deadlockCount" : {
                   "r" : NumberLong(0),
                   "w" : NumberLong(0),
                   "R" : NumberLong(0),
                   "W" : NumberLong(0)
                }
             },
             "MMAPV1Journal": {
                ...
             },
             "Database" : {
                ...
             },
             ...
         }
       },
       ...
   ],
   "fsyncLock": <boolean>,
   "info": <string>
}

https://docs.mongodb.com/v3.0/reference/method/db.currentOp/#output-fields

The locks document reports the type and mode of locks the operation currently holds. The possible lock types are as follows:

  • Global represents global lock.
  • MMAPV1Journal represents MMAPv1 storage engine specific lock to synchronize journal writes; for non-MMAPv1 storage engines, the mode for MMAPV1Journal is empty.
  • Database represents database lock.
  • Collection represents collection lock.
  • Metadata represents metadata lock.
  • oplog represents lock on the oplog.

The possible modes are as follows:

  • R represents Shared (S) lock.
  • W represents Exclusive (X) lock.
  • r represents Intent Shared (IS) lock.
  • w represents Intent Exclusive (IX) lock.

ii. mongotop
https://docs.mongodb.com/v3.0/reference/program/mongotop/#options

–locks returns an error when called against a mongod instance that does not report lock usage.

iii. mongostat, and/or
https://docs.mongodb.com/v3.0/reference/program/mongostat/#fields

locked
Changed in version 3.0.0: Only appears when mongostat runs against pre-3.0 versions of MongoDB instances.
The percent of time in a global write lock.

4、产生数据库锁的操作

OperationLock Type
db.eval()
Deprecated since version 3.0.
Write lock. The db.eval() method takes a global write lock while evaluating the JavaScript function. To avoid taking this global write lock, you can use the eval command with nolock: true.
eval
Deprecated since version 3.0.
Write lock. By default, eval command takes a global write lock while evaluating the JavaScript function. If used with nolock: true, the eval command does not take a global write lock while evaluating the JavaScript function. However, the logic within the JavaScript function may take write locks for write operations.

5、存储引擎

MMAPv1 存储引擎
https://docs.mongodb.com/v3.0/core/mmapv1/

WiredTiger 存储引擎

https://docs.mongodb.com/v3.0/core/wiredtiger/
提供了文档级别的写并发控制
使用了多版本并发控制(MVCC)。操作开始之时,WiredTiger 提供了一个时间点快照。快照提供了内存数据的一致性视图。
每 60 秒或 2G Journal 发生一次检查点操作

6、事务

https://docs.mongodb.com/v3.0/faq/fundamentals/#does-mongodb-support-transactions
不支持多文档事务
在单个文档上的操作是原子的


MongoDB 3.2 并发机制

1、查看锁状态

i. mongostat, and/or

lr
New in version 3.2.
Only for MMAPv1 Storage Engine. The percentage of read lock acquisitions that had to wait.mongostat displays lr|lw if a lock acquisition waited.
lw
New in version 3.2.
Only for MMAPv1 Storage Engine. The percentage of write lock acquisitions that had to wait.mongostat displays lr|lw if a lock acquisition waited.
lrt
New in version 3.2.
Only for MMAPv1 Storage Engine. The average acquire time, in microseconds, of read lock acquisitions that waited. mongostat displays lrt|lwt if a lock acquisition waited.
lwt
New in version 3.2.
Only for MMAPv1 Storage Engine. The average acquire time, in microseconds, of write lock acquisitions that waited. mongostat displays lrt|lwt if a lock acquisition waited.

2、读未提交数据

https://docs.mongodb.com/manual/release-notes/3.2/#readconcern
新增 readConcern 选项
WiredTiger:

  • readConcern=majority 只能读取到已被 majority 确认写入磁盘的数据
  • readConcern=local 可读取未经确认的数据(同旧版本)

MMAPv1:

  • readConcern=local 只有这一个选项

3、存储引擎

默认为 WiredTiger


参考

-eof-

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值