MongoDB中的讀寫鎖


1. MongoDB 使用的鎖

MongoDB 使用的是“readers-writer”鎖, 可以支持並發但有很大的局限性
當一個讀鎖存在,許多讀操作可以使用這把鎖,然而, 當一個寫鎖的存在,一個單一的寫操作會”exclusively“持有該鎖,同一時間其它寫操作不能使用共享這個鎖;
舉個例子,假設一個集合里有10個文檔,多個update操作不能並發在這個集合上,即使是更新不同的文檔。


2. 鎖的粒度

在 2.2 版本以前,一個mongodb實例一個寫鎖,多個讀鎖。也就是說mongod 只有全局鎖(鎖定一個server);

在2.2-3.0的版本,一個數據庫一個寫鎖,多個讀鎖。例如如果一個 mongod 實例上有 5 個庫,如果只對一個庫中的一個集合執行寫操作,那么在寫操作過程中,這個庫被鎖;而其它 4 個庫不影響。相比 RDBMS 來說,這個粒度已經算很大了!

在3.0之后的版本,WiredTiger提供了文檔(不是集合)級別的鎖。

更新:MongoDB 3.4版本,寫操作的鎖定粒度在表中數據記錄(document)級別,即使操作對象可能是多條數據,每條數據在被寫入時都會被鎖定,防止其他進程寫入;但是寫操作是非事務性的,即寫入多條數據,即使當前寫入操作還沒有完成,前面已經寫入的數據也可以被其他進程修改。除非指定了$isolated,一次寫入操作影響的數據無法在本次操作結束之前被其他進程修改。
$isolated也是非事務性的,即如果寫入過程出錯,已經完成的寫入操作不會被rollback;另外,$isolated需要額外的鎖,無法用於sharded方式部署的集群。
官網文檔鏈接

MongoDB高吞吐的原因:

  • MongoDB 沒有完整事務支持,操作原子性只到單個 document 級別,所以通常操作粒度比較小;
  • MongoDB 鎖實際占用時間是內存數據計算和變更時間,通常很快;
  • MongoDB 鎖有一種臨時放棄機制,當出現需要等待慢速 IO 讀寫數據時,可以先臨時放棄,等 IO 完成之后再重新獲取鎖。

 

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.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM