mongodb常見問題——併發

MongoDB允許多個客戶端讀取和寫入相同的數據。爲了確保一致性,它使用鎖定和其他併發控制措施來防止多個客戶端同時修改同一條數據。總之,這些機制保證對單個文檔的所有寫入完全或根本不發生,並且客戶端永遠不會看到數據的不一致視圖。

MongoDB使用何種類型的鎖?

MongoDB使用多粒度的鎖,允許操作鎖定全局,數據庫或集合級別,並允許各個存儲引擎在集合級別下實現自己的併發控制(例如,在WiredTiger中的文檔級別鎖) 。

MongoDB使用讀-寫鎖,允許併發讀操作以共享的方式訪問資源(如一個數據庫或一個集合),但在MMAPv1中,對單個寫入操作採取獨佔(排它)的訪問方式。(現一般情況下不推薦使用MMAPv1)

除了用於讀取的共享鎖(S)模式和用於寫入操作的排它鎖(X)模式之外,意向共享鎖(IS)和意向排它鎖(IX)模式指示了使用更精細的鎖定粒度來讀取或寫入資源的意圖 。當以某個粒度鎖定資源時,所有更高層面都使用意向鎖

例如,在鎖定集合以進行寫入時(使用排它鎖(X)模式),必須在意向排它鎖(IX)模式下鎖定相應的數據庫鎖和全局鎖。單個數據庫可以同時鎖定在IS(意向共享鎖)和IX(意向排它鎖)模式,但是(X)不能與任何其他模式共存,並且共享鎖(S)只能與意圖共享(IS)鎖共存。

鎖是公平的,讀取和寫入按順序排隊。但是,爲了優化吞吐量,當一個請求被授予時,所有其他兼容請求將同時被授予,在衝突請求之前釋放它們。例如,考慮X鎖(排它鎖)被釋放的情況,其中衝突隊列包含以下項:

IS→IS→X→X→S→IS

在嚴格的先進先出(FIFO)排序中,只授予前兩種IS模式。然而,MongoDB實際上將授予所有IS和S模式,一旦它們全部完成,它將授予X,即使新的IS或S請求在此期間已進入排隊。由於授權將始終在隊列中提前移動所有其他請求,因此任何請求都不可能存在飢餓等待問題。

db.serverStatus()db.currentOp()輸出中,鎖定模式被表示如下:

鎖模式 描述
R 代表共享鎖(S)
W 代表排它鎖(X)
r 代表意向共享鎖(IS)
w 代表意向排它鎖(IX)

MongoDB中鎖的粒度有多細?

在版本3.0中更改。

對於WiredTiger

從版本3.0開始,MongoDB可以使用WiredTiger存儲引擎。

對於大多數讀寫操作,WiredTiger使用樂觀鎖併發控制。WiredTiger僅在全局,數據庫和集合級別使用意向鎖。當存儲引擎檢測到兩個操作之間的衝突時,其中一個會引發寫入衝突,導致MongoDB(對用戶而言透明)重試該操作。

一些全局操作(通常是涉及多個數據庫的短期操作)仍然需要全局“實例範圍”鎖定。其他一些操作(例如刪除集合)仍需要獨佔數據庫鎖。

對於MMAPv1

MMAPv1存儲引擎在3.0版本系列中使用了集合級別鎖,這是對早期版本的改進,在早期版本中數據庫級別鎖是最細粒度的鎖。第三方存儲引擎可以使用集合級鎖或實現自己的更細粒度的併發控制。

舉個例子,如果一個使用MMAPv1存儲引擎的數據庫中有六個集合,有一個採用集合級寫鎖的操作,則其他五個集合仍可用於讀取和寫入操作。一個排它數據庫級別鎖使得所有六個集合在持有鎖的操作期間不可用。

如何在我的mongod實例上看到鎖的狀態?

要報告鎖對象上的鎖使用率信息,請使用以下任一方法:
db.serverStatus()
db.currentOp()
mongotop
mongostat
MongoDB Cloud ManagerOps Manager,MongoDB企業版提供的先進的解決方案

具體來說,serverStatus輸出中locks子文檔或當前操作報告中(current operation reporting)的locks字段 ,提供了可以深入瞭解實例中鎖的類型和鎖爭用的數量。

db.serverStatus()db.currentOp()輸出中,所述鎖定模式被表示如下:

鎖模式 描述
R 代表共享鎖(S)
W 代表排它鎖(X)
r 代表意向共享鎖(IS)
w 代表意向排它鎖(IX)

要終止操作,請使用db.killOp()

讀取或寫入操作是否會讓渡(yield)鎖?

在某些情況下,讀寫操作可以讓渡(yield)它們持有的鎖。

長時間運行的讀寫操作(例如查詢,更新和刪除)在許多條件下都會進行讓渡(yield)。MongoDB如果單個修改文檔的操作,影響帶有multi參數修改多個文檔update()操作,MongoDB也會讓渡鎖。

對於支持文檔級併發控制的存儲引擎,例如WiredTiger,當使用意向鎖訪問存儲時不需要讓渡(yield),因爲該鎖是全局,數據庫和集合級別,不會阻止其他讀寫操作。但是,操作會定期產生讓渡(yield),例如:

  • 避免長時間執行的存儲性事務,因爲這些可能需要在內存中保存大量數據;
  • 作爲中斷響應點(interruption points),以便你可以殺死長時間運行的操作;
  • 允許需要對集合進行排它訪問的操作得到執行,例如索引/集合的刪除和創建。

MongoDB的MMAPv1存儲引擎使用基於其訪問模式的啓發式方法來預測在執行讀取之前數據是否可能存在於物理內存中。如果MongoDB 預測數據不在物理內存中,則當MongoDB將數據加載到內存中時,操作將讓渡鎖。一旦數據在內存中可用,操作將重新獲取鎖以完成操作。

一些常見的客戶端操作會採取什麼樣的鎖定?

下表列出了一些操作以及它們在文檔級鎖存儲引擎中的鎖類型:

操作 數據庫級別鎖 集合級別鎖
查詢(query) r (意向共享鎖(IS)) r (意向共享鎖(IS))
插入數據(insert) w (意向排它鎖(IX)) w (意向排它鎖(IX))
刪除數據(remove) w (意向排它鎖(IX)) w (意向排它鎖(IX))
更新數據(update) w (意向排它鎖(IX)) w (意向排它鎖(IX))
執行聚合操作(aggregation) r (意向共享鎖(IS)) r (意向共享鎖(IS))
創建索引(前臺創建Foreground) W (排它鎖(X))  
創建索引(後臺創建Background) w (意向排它鎖(IX)) w (意向排它鎖(IX))
列出集合列表(List collections) r (意向共享鎖(IS))  


版本4.0中修改.
Map-reduce操作        |                W (排它鎖(X) 和R 共享鎖(IS)       |          w (意向排它鎖(IX)) and r (意向共享鎖(IS))

哪些管理命令鎖定數據庫?

某些管理命令可以在很長一段時間內排它鎖定數據庫。在某些部署中,對於大型數據庫,您可以考慮使mongod實例脫機,以便客戶端不受影響。例如,如果 mongod副本集的一部分,請執行mongod脫機操作,並在維護過程中,讓副本集的其他成員服務請求負載。

以下管理操作需要在數據庫級別進行長時間的排它鎖定:

命令 方法
cloneCollectionAsCapped

compact

convertToCapped

copydb. 該操作可能鎖定所有的數據庫. 查看 MongoDB會鎖定多個數據庫嗎?
db.copyDatabase(). 該操作可能鎖定所有的數據庫. 查看 MongoDB會鎖定多個數據庫嗎?

create 當創建一個特別大的定容集合(capped collection,例如數GB級別) db.createCollection() 當創建一個特別大的定容集合(capped collection,例如數GB級別)
createIndexes (沒有設置background參數時) db.collection.createIndex() anddb.collection.createIndexes() (沒有設置background參數時)

repairDatabase
db.repairDatabase()

以下管理操作會鎖定數據庫,但是隻會鎖定很短的時間:

命令 方法
authenticate
db.auth()

createUser
db.createUser()

dropIndexes
db.collection.dropIndex()

getLastError
db.getLastError()

isMaster
db.isMaster()

replSetGetStatus
rs.status()

renameCollection
db.collection.renameCollection()

serverStatus
db.serverStatus()

參考:
MongoDB會鎖定多個數據庫嗎?

MongoDB操作是否鎖定多個數據庫?

以下MongoDB操作採用全局排它鎖(譯者注:即會鎖定所有的數據庫):
 db.copyDatabase()獲取全局排它鎖(global exclusive (W) lock),將阻塞其他操作直到該操作完成。
 db.repairDatabase()獲取全局排它鎖(global exclusive (W) lock),將阻塞其他操作直到該操作完成。
 從MongoDB 4.0開始,db.collection.reIndex()獲取 獲取全局排它鎖(globalexclusive (W) lock),將阻塞其他操作直到該操作完成。
 用戶身份驗證對於使用 2.6用戶憑據的部署,需要在admin庫上獲取一個讀鎖。對於使用2.4模式進行用戶憑據的部署,身份驗證會鎖定 admin數據庫同時也會鎖定用戶正在訪問的數據庫。
 對副本集primary節點的所有寫入操作,會短時間鎖住寫入的目標數據庫以及local數據庫。鎖定local數據庫,允許 mongod佔用操作總時間的一小部分來寫入primary節點的oplog。
 副本集成員狀態轉換採用全局排它鎖。

分片如何影響併發?

分片通過將集合分佈在多個mongod實例,提高併發的能力,允許分片服務器(即mongos進程)來併發的執行鍼對下游mongod 實例的任意數量的操作。

在分片羣集中,鎖定應用於每個單獨的分片,而不是整個羣集; 即每個mongod實例獨立於分片集羣中的其他實例並使用自己的 鎖。一個 mongod實例上的操作不會阻止任何其他實例上的操作。

併發性如何影響副本集的primay節點?

對於副本集,當MongoDB寫入主節點上的集合時 ,MongoDB還會寫入主節點的oplog—local數據庫中的特殊集合。因此,MongoDB必須鎖定集合所在的數據庫和local 數據庫。mongod必須同時鎖定這兩個庫來保持數據庫一致性,並確保寫入操作,甚至包括複製,是“all-or-nothing”的操作。

寫入副本集時,鎖的範圍適用於主節點(primary)。

併發性如何影響副本集的secondary節點?

在進行副本複製同步時,MongoDB不會將寫入連續的應用到從節點(secondaries)。從節點批量收集oplog記錄,然後並行應用這些批處理。從節點在應用寫入操作時不允許讀取,並按照它們在oplog中出現的順序應用這些寫入操作。

MongoDB是否支持事務?

因爲單個文檔可以包含關聯數據(譯者注:通過內嵌文檔或數組的方式),而這些關聯數據在關係模型中是使用單獨父子表進行建模的,MongoDB的單文檔原子操作已經提供了滿足大多數應用程序的數據完整性需求的事務語義。可以在單個操作中寫入一個或多個字段,包括對多個子文檔和數組元素的更新。MongoDB提供的單文檔操作原子性保證確保在文檔更新時完全隔離; 任何錯誤都會導致操作回滾,以便客戶端收到文檔的一致視圖。

從版本4.0開始,對於需要原子性來更新多個文檔或讀取多個文檔之間的一致性的情況,MongoDB 爲副本集提供多文檔事務,並計劃在MongoDB 4.2中提供分片集羣的事務。

重要

在大多數情況下,多文檔事務比單個文檔寫入產生更高的性能成本,並且多文檔事務的可用性不應該取代有效的模式設計。對於許多場景, 非規範化數據模型(嵌入式文檔和數組)將繼續爲您的數據和用例提供最佳選擇。也就是說,對於許多場景,合理的數據建模將最大限度地減少對多文檔事務的需求。

[2] 我們產品所描述的任何特性或功能的開發,發佈和時間由我們自行決定。此信息僅用於概述我們的一般產品方向,不應依賴於做出購買決定,也不是承諾,或爲法律義務提供任何材料,代碼或功能。

MongoDB提供了什麼樣的隔離保證?

根據ReadConcern參數設置,客戶端可以在寫入持久化之前查看寫入結果。要控制是否可以回滾讀取的數據,客戶端可以使用readConcern選項。

發佈了15 篇原創文章 · 獲贊 6 · 訪問量 3580
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章