mongodb的使用者在遇到性能問題時,經常會關注到 serverstatus.globallock 名額,但對名額的含義不是很明确,本文會深入解釋下 globallock 名額的含義。
a document that reports on the database’s lock state.
generally, the locks document provides more detailed data on lock uses.
the time, in microseconds, since the database last started and created the globallock. this is roughly equivalent to total server uptime.
a document that provides information concerning the number of operations queued because of a lock.
the total number of operations queued waiting for the lock (i.e., the sum of globallock.currentqueue.readers and globallock.currentqueue.writers).
a consistently small queue, particularly of shorter operations, should cause no concern. the globallock.activeclients readers and writers information provides contenxt for this data.
the number of operations that are currently queued and waiting for the read lock. a consistently small read-queue, particularly of shorter operations, should cause no concern.
the number of operations that are currently queued and waiting for the write lock. a consistently small write-queue, particularly of shorter operations, is no cause for concern.
a document that provides information about the number of connected clients and the read and write operations performed by these clients.
use this data to provide context for the globallock.currentqueue data.
the total number of active client connections to the database (i.e., the sum of globallock.activeclients.readers and globallock.activeclients.writers).
the number of the active client connections performing read operations.
the number of active client connections performing write operations.
mongod上每個連接配接會對應一個client對象,client裡包含目前鎖的狀态,初始為 kinactive,根據請求及并發狀況的不同,會進入到其他的狀态,核心邏輯在 lockglobalbegin 裡實作。
而 serverstatus.globallock 其實根據這個鎖的狀态進行導出
2018-03-13 update
擷取 client 狀态時,已經擷取到 ticket 的 reader/writer 如果在等鎖,也會認為是 queued 狀态,這個之前忽略了。
總結一下
mongodb 加鎖時,有四種模式【mode_is、mode_ix、mode_s、mode_x】,mode_s, mode_x 很容易了解,分别是互斥讀鎖、互斥寫鎖,mode_is、mode_ix是為了實作層次鎖模型引入的,稱為意向讀鎖、意向寫鎖,鎖之間的競争情況如上圖所示。
mongodb在加鎖時,是一個層次性的管理方式,從 globallock ==> dblock ==> collecitonlock ... ,比如我們都知道mongodb wiredtiger是文檔級别鎖,那麼讀寫并發時,加鎖就類似如下
根據上圖的競争情況,is和ix是無需競争的,是以讀寫請求可以在沒有競争的情況下,同時傳到wiredtiger引擎去處理。
再舉個栗子,如果一個前台建索引的操作跟一個讀請求并發了
根據競争表,mode_x和mode_is是要競争的,這也就是為什麼前台建索引的過程中讀是被阻塞的。
我們今天介紹的 globallock 對應上述的第一步,在globallock這一層,隻關心是讀鎖、還是寫鎖,不關心是互斥鎖還是意向鎖,是以 globallock 這一層是不存在競争的。那麼 globallock 裡的幾個名額到底意味着什麼?
從上述的代碼可以發現,globallockbegin裡(基本所有的資料庫讀寫請求都要走這個路徑)決定了globallock的狀态轉換,核心邏輯如下
上述代碼裡,如果holder不為空,client會先進去kqueuedreader或kqueuedwriter狀态,然後擷取一個ticket,擷取到後轉換為kactivereader或kactivewriter狀态。這裡的ticket是什麼東西?
這裡的ticket是引擎可以設定的一個限制。正常情況下,如果沒有鎖競争,所有的讀寫請求都會被pass到引擎層,這樣就有個問題,你請求到了引擎層面,還是得排隊執行,而且不同引擎處理能力肯定也不同,于是引擎層就可以通過設定這個ticket,來限制一下傳到引擎層面的最大并發數。比如
wiredtiger設定了讀寫ticket均為128,也就是說wiredtiger引擎層最多支援128的讀寫并發(這個值經過測試是非常合理的經驗值,無需修改)。
mmapv1引擎并沒有設定ticket的限制,也就是說用mmapv1引擎時,globallock的currentqueue會一直是0.
globallock完成後,client就進入了kactivereader或kactivewriter中的一種狀态,這個就對應了globallock.activerclients字段裡的名額,接下來才開始lockbegin,加db、collection等層次鎖,更底層的鎖競争會間接影響到globallock。
serverstatus.globallock 或者 mongostat (qr|qw ar|aw名額)能檢視mongod globallock的各個名額情況。
wiredtiger限制傳遞到引擎層面的最大讀寫并發數均為128(合理的經驗值,通常無需調整),如果超過這個門檻值,排隊的請求就會展現在globallock.currentqueue.readers/writers裡。
如果globallock.currentqueue.readers/writers個值長時間都不為0(此時globallock.activeclients.readers/writers肯定是持續接近或等于128的),說明你的系統并發太高(或者有長時間占用互斥鎖的請求比如前台建索引),可以通過優化單個請求的處理時間(比如建索引來減少collscan或sort),或更新後端資源(記憶體、磁盤io能力、cpu)來優化。
globallock.activeclients.readers/writers 持續不為0(但沒達到128,此時currentqueue為空),并且你覺得請求處理已經很慢了,這時也可以考慮2中提到的優化方法。