MongoDB面試指南之併發

MongoDB面試指南之併發

併發

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

MongoDB使用什麼類型的鎖?

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

MongoDB使用讀寫鎖,允許併發的讀寫器共享對資源(如數據庫或集合)的訪問,但在MMAPv1中,只允許對單個寫操作進行獨佔訪問。

除了用於讀操作的共享鎖定模式和用於寫操作的獨佔鎖定模式外,意圖共享(IS)和意圖獨佔(IX)模式表示使用更細粒度的鎖讀寫資源的意圖。當鎖定在某個粒度時,所有更高級別的鎖都使用一個intent鎖進行鎖定。

例如,在爲寫入鎖定集合時(使用模式X),必須在intent exclusive (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() 輸出中, 鎖模式的含義如下:

Lock Mode Description
R 共享鎖 Shared (S) lock
W 排它鎖 Exclusive (X) lock
r 意向共享鎖 Intent Shared (IS) lock
w 意向排它鎖 Intent Exclusive (IX) lock

在MongoDB中鎖的粒度有多大

WiredTiger引擎

從3.0版本開始,MongoDB使用WiredTiger存儲引擎。對於大多數讀寫操作,WiredTiger使用樂觀併發控制。WiredTiger只在全局、數據庫和collection集合級別使用意圖鎖。當存儲引擎檢測到兩個操作之間的衝突時,其中一個操作將引發寫衝突,從而導致MongoDB透明地重試該操作。
一些全局操作(通常是涉及多個數據庫的短期操作)仍然需要全局“實例級”鎖。其他一些操作,比如刪除一個集合,仍然需要一個獨佔的數據庫鎖。

MMAPv1引擎

MMAPv1存儲引擎在3.0發行版系列中使用了集合級鎖,這是對早期版本的改進,在早期版本中,數據庫鎖是最細粒度的鎖。第三方存儲引擎可以使用集合級鎖定,也可以實現它們自己的細粒度併發控制。
例如,如果在使用MMAPv1存儲引擎的數據庫中有6個集合,並且某個操作採用了集合級別的寫鎖,那麼其他5個集合仍然可以用於讀寫操作。獨佔數據庫鎖使所有6個集合在持有鎖的操作期間不可用。

如何查看mongod實例上的鎖的狀態

要報告鎖的鎖使用信息,請使用下列任何方法:

  • db.serverStatus()
  • db.currentOp()
  • mongotop
  • mongostat, and/or
  • MongoDB雲管理器 or Ops Manager, an on-premise solution available in MongoDB Enterprise Advanced

具體地說,serverStatus輸出中的locks文檔或當前操作報告中的locks字段提供了對鎖類型和mongod實例中鎖爭用數量的深入瞭解。

終止操作db.killOp().

讀或寫操作是否會產生鎖

在某些情況下,讀和寫操作可能會產生鎖。長時間運行的讀和寫操作,例如查詢、更新和刪除,在許多情況下都會產生。在寫操作中,MongoDB操作還可以在單個文檔修改之間產生鎖,這些修改會影響多個文檔,比如使用multi參數的update()。

對於支持文檔級併發控制的存儲引擎(如WiredTiger),在訪問存儲時不需要產生結果,因爲意圖鎖(在全局、數據庫和集合級別持有)不會阻塞其他讀取器和寫入器。但是,業務將定期產生下列結果: 對於支持文檔級併發控制的存儲引擎(如WiredTiger),在訪問存儲時不需要產生結果,因爲意圖鎖(在全局、數據庫和集合級別持有)不會阻塞其他讀取器和寫入器。但是,以下操作會產生鎖:

  • 爲了避免長時間的存儲事務,因爲這些事務可能需要在內存中保存大量數據;
  • 作爲中斷點,可以終止長時間運行的操作;
  • 允許需要對集合進行獨佔訪問的操作,如索引/集合刪除和創建

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

一些常見的客戶端操作佔用哪些鎖

下表列出了一些操作和它們用於文檔級鎖定存儲引擎的鎖的類型

Operation Database Collection
Issue a query r (Intent Shared) r (Intent Shared)
Insert data w (Intent Exclusive) w (Intent Exclusive)
Remove data w (Intent Exclusive) w (Intent Exclusive)
Update data w (Intent Exclusive) w (Intent Exclusive)
Perform Aggregation r (Intent Shared) r (Intent Shared)
Create an index (Foreground) W (Exclusive)  
Create an index (Background) w (Intent Exclusive) w (Intent Exclusive)
List collections R (Shared)  
Map-reduce W (Exclusive) and R (Shared) w (Intent Exclusive) and r (Intent Shared)

哪些管理命令鎖定數據庫

某些管理命令可以在較長時間內獨佔鎖定數據庫。在一些部署中,對於大型數據庫,您可以考慮將mongod實例脫機,這樣客戶端就不會受到影響。例如,如果一個mongod是一個複製集的一部分,那麼在維護過程中,讓mongod脫機並讓集合服務的其他成員加載它。

下列管理操作需要在數據庫級長時間使用獨佔鎖:

Commands Methods
cloneCollectionAsCapped  
compact  
convertToCapped  
copydb. This operation may lock all databases. See Does a MongoDB operation ever lock more than one database?. db.copyDatabase(). This operation may lock all databases. See Does a MongoDB operation ever lock more than one database?.
create when creating a very large (i.e. many gigabytes) capped collection db.createCollection() when creating a very large (i.e. many gigabytes) capped collection
createIndexes for indexes without background set to true db.collection.createIndex() and db.collection.createIndexes()
reIndex db.collection.reIndex()
repairDatabase db.repairDatabase()

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

Commands Methods
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操作鎖定多個數據庫:

  • db.copyDatabase() 必須立即鎖定整個mongod實例。
  • db.repairDatabase() 獲取一個全局寫鎖,並將阻塞其他操作,直到它完成
  • User authentication對於使用2.6用戶憑證的部署,需要管理數據庫上的讀鎖。對於使用2.4模式進行用戶憑證的部署,身份驗證將鎖定管理數據庫和用戶正在訪問的數據庫。
  • 對複製集的主鎖的所有寫操作,包括接收寫操作的數據庫和短時間內的本地數據庫。本地數據庫的鎖允許mongod寫入主服務器的oplog,佔操作總時間的一小部分。
  • 複製集成員狀態轉換採用全局exlusive lock。

分片如何影響併發性

分片通過在多個mongod實例上分佈集合來提高併發性,允許shard服務器(即mongos進程)併發地執行任意數量的操作到各個下游mongod實例。

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

當寫入副本集時,鎖的作用域應用於主副本集。

併發性如何影響複製集主節點?

在複製中,MongoDB不將寫操作串行地應用於Secondary服務器。Secondary機構成批收集oplog條目,然後並行應用這些批。其次,在應用寫操作時不允許讀操作,並且按寫操作在oplog中出現的順序應用它們。

MongoDB支持事務嗎

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

從4.0版本開始,對於需要對多個文檔進行更新或需要對多個文檔進行讀操作之間保持一致性的情況,MongoDB爲副本集提供多文檔事務,而針對切分集羣的事務安排在MongoDB 4.2中。

要點

在大多數情況下,與單個文檔寫入相比,多文檔事務會帶來更大的性能成本,而且多文檔事務的可用性不應該代替有效的模式設計。對於許多場景,非規範化數據模型(嵌入文檔和數組)對於您的數據和用例來說仍然是最優的。也就是說,對於許多場景,適當地對數據建模將最小化對多文檔事務的需求

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

根據讀關注點,客戶端可以在寫操作持久之前看到寫操作的結果。要控制讀取的數據是否可以回滾,客戶端可以使用readConcern選項。

歡迎大家關注微信公衆號: C2H說

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章