MongoDB中的讀寫鎖
1. MongoDB 使用的鎖
MongoDB 使用的是“readers-writer”鎖, 可以支援併發但有很大的侷限性
當一個讀鎖存在,許多讀操作可以使用這把鎖,然而, 當一個寫鎖的存在,一個單一的寫操作會”exclusively“持有該鎖,同一時間其它寫操作不能使用共享這個鎖;
舉個例子,假設一個集合裡有10個文件,多個update操作不能併發在這個集合上,即使是更新不同的文件。
2. 鎖的粒度
在 2.2 版本以前,mongod 只有全域性鎖(鎖定一個server);
從2.2 版本開始,大部分讀寫操作只鎖一個庫(database),相對之前版本,這個粒度已經下降,例如如果一個 mongod 例項上有 5 個庫,如果只對一個庫中的一個集合執行寫操作,那麼在寫操作過程中,這個庫被鎖;而其它 5 個庫不影響。相比 RDBMS 來說,這個粒度已經算很大了!
更新:MongoDB 3.4版本,寫操作的鎖定粒度在表中資料記錄(document)級別,即使操作物件可能是多條資料,每條資料在被寫入時都會被鎖定,防止其他程序寫入;但是寫操作是非事務性的,即寫入多條資料,即使當前寫入操作還沒有完成,前面已經寫入的資料也可以被其他程序修改。除非指定了$isolated,一次寫入操作影響的資料無法在本次操作結束之前被其他程序修改。
$isolated也是非事務性的,即如果寫入過程出錯,已經完成的寫入操作不會被rollback;另外,$isolated需要額外的鎖,無法用於sharded方式部署的叢集。
官網文件連結
3. 如何檢視鎖的狀態
db.serverStatus()
db.currentOp()
mongotop # 類似top命令,每秒重新整理
mongostat
the MongoDB Monitoring Service (MMS)
4. 哪些操作會對資料庫產生鎖?
下表列出了常見資料庫操作產生的鎖。
操作 | 鎖定型別 |
查詢 | 讀鎖 |
通過cursor讀取資料 | 讀鎖 |
插入資料 | 寫鎖 |
刪除資料 | 寫鎖 |
修改資料 | 寫鎖 |
Map-reduce | 讀寫鎖均有,除非指定為non-atomic,部分mapreduce任務可以同時執行(猜測是生成的中間表不衝突的情況下) |
新增index | 通過前臺API新增index,鎖定資料庫一段時間 |
db.eval() | 寫鎖,同時阻塞其他執行在MongoDB上的JavaScript程序 |
eval | 寫鎖,如果設定鎖定選項是nolock,則不會有些鎖,而且eval無法向資料庫寫入資料 |
aggregate() | 讀鎖 |
附上原文:
Operation Lock Type
Issue a query Read lock
Get more data from a cursor Read lock
Insert data Write lock
Remove data Write lock
Update data Write lock
Map-reduce Read lock and write lock, unless operations are specified as non-atomic. Portions of map-reduce jobs can run concurrently.
Create an index Building 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.
eval Write 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
5. 哪些資料庫管理操作會鎖資料庫?
某些資料庫管理操作會 exclusively 鎖住資料庫,以下命令需要申請 exclusively 鎖,並鎖定一段時間
db.collection.ensureIndex(),
reIndex,
compact,
db.repairDatabase(),
db.createCollection(), when creating a very large (i.e. many gigabytes) capped collection,
db.collection.validate(),
db.copyDatabase() # 可能會鎖定所有資料庫(database)
以下命令需要申請 exclusively 鎖,但鎖定很短時間。
db.collection.dropIndex(),
db.collection.getLastError(),
db.isMaster(),
rs.status() (i.e. replSetGetStatus,)
db.serverStatus(),
db.auth(), and
db.addUser().
備註:可見,一些檢視命令也會鎖庫,在比較繁忙的生產庫中,也會有影響的。
6. MongoDB內部可能鎖住多個庫的操作
以下資料庫內部操作會鎖定多個庫。
日誌管理 MongoDB的內部操作,每個一段時間就鎖定所有資料庫,所有的資料庫共享一份日誌
使用者認證 鎖定admin資料庫和使用者正在申請訪問的資料庫
所有寫入備份資料庫(replica)的操作都會鎖定寫入目標資料庫和本地資料庫,本地資料庫的寫入鎖允許寫入主節點的oplog
原文:
Journeying, 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.