<b>演講嘉賓簡介:</b>
<b>陳柯任(花名:莫歸)</b>,阿裡巴巴進階開發工程師,曾在大衆點評從事MongoDB與MySQL相關運維和自動化研發,現就職于阿裡雲MongoDB團隊,主要緻力于分布式存儲和NoSQL資料庫相關領域。
<b> </b>
<b>以下内容根據演講嘉賓視訊分享以及</b><b>PPT</b><b>整理而成</b>
本次分享主要圍繞以下三個方面:
一.MongoDB名額分類及檢視指令
二.關鍵名額詳解
三.場景診斷
<b>一.MongoDB名額分類及檢視:</b>
MongoDB程序狀态名額指令:db.serverStatus(),主要資料性能檢視來源
MongoDB資料檔案狀态名額指令: db.stats(), db.c.stats(),檢視檔案大小,存儲空間大小等等
MongoDB副本集狀态名額指令: rs.status()
<b>1. </b>
MongoDB資料檔案狀态名額解析:

db.stats()實際是一個文法糖,在底層實作是db.runCommand({dbstats:1,scale:scale})的指令,其中包含dbstats與scale兩個參數,dbstats是輸出值,scale可以控制輸出值機關,一般預設dbstats為1,scale為byte,則此時以byte為機關輸出dbstats。另一種方法db.c.stats()與db.stats()方法相同,在此不多做贅述。
以上為db.stats()調用出的資料庫狀态圖檔,共分以上名額,這其中不少同學曾對dataSize與storageSize的意義感到迷惑。事實上,dataSize指的是資料本身即未壓縮時的大小,而storageSize則指的是資料落盤時的大小,資料在落盤時會執行一些相應的壓縮算法,比如MongoDB本身預設的snappy壓縮算法,壓縮率在4到5倍之間,這便是為什麼dataSize往往比storageSize大的原因。當使用者發現這兩個數值相近時,很有可能是資料檔案出現了檔案空洞,這時建議使用者進行compact或者重搭一類的辦法消除檔案空洞。indexSize名額指的是索引落盤的大小,即索引的實體存儲的大小。利用IndexSize與storageSize相加,我們就能得到對應資料庫占用磁盤的大小,同時用dataSize除以storageSize我們可以判斷壓縮比的值,若壓縮比值過小,很有可能出現了資料空洞,需要我們對其用compact指令進行處理。
<b>2. </b>
MongoDB副本集狀态名額解析:
用rs.status(),即内部實作db.runCommand({replSetGetStatus:1})指令可檢視資料庫副本集的狀态。其中set名額為副本集的名稱,term名額為選舉版本号,當叢集進行切換或選舉時,系統復原時會使用term對版本号進行判斷。optime名額記錄了每個目前執行個體oplog最後的操作時間,通過這個時間與主庫的時間進行比較可以得到主從庫的延遲。syncingTo名額表示目前結點的同步源,一般情況下是由MongoDB自身各個結點的健康狀态生成的。
<b>3. MongoDB程序狀态名額解析:(以MongoDB 3.4版本為例)</b>
db.serverStatus()指令,即内部值db.runCommand(serverStatus:1,option)
option參數使得serverStatus()指令可以追加各種的filter,用以強制系統輸出我們希望看到的資料。
<b>二.關鍵名額詳解:</b>
下面我們對程序狀态名額中比較重要的名額進行一一解讀:
1.
asserts:
asserts本身值得注意的事項較少,這其中asserts|user是一個很有趣的名額,它記錄了使用者執行指令錯誤的次數,如果該值較高,說明使用者指令記憶不清晰,建議多讀一些指令文檔。其他的一些值例如:asserts|msg,asserts|warning等通常為0值,當這些值不為0時,或多或少反映系統存在着某些問題。
2.
connections:
connections名額标注的是連接配接的狀況,其中available與current均顯示的是目前的值,available表示資料庫目前可用的連接配接量,當其值過低時,可能是出現了連接配接池過滿的現象,通過改進資料庫配置中的maxConnection或改善一些慢查詢占用的連接配接可解決此問題。current表示資料庫目前的連接配接數,當這個值高時,即出現了與available過低一樣的問題,參考以上的解決方法同樣可以解決此種問題。另一名額totalCreated記錄了MongoDB啟動後一共建立過多少個連接配接,通過采集工具做delta後我們可以得到每秒的建立量,當每秒的建立量過大時,說明我們的資料庫采用了過多的短連進行連接配接,由于MongoDB基于線程模型的特點,過多的短連會使資料庫的性能下降,希望大家多重視這個名額。
3.
globalLock:
globalLock中的值同樣表示的是目前的值,相較于connections, globalLock的值均由server内部的狀态值中取出。其中activeClients主要描述了目前請求用戶端操作鎖的情況,currentQueue描述了目前進行有關鎖的操作的隊列情況,當這其中有過高名額時,說明我們的業務中正有大的有關鎖部的操作影響着資料庫的性能。
4.
locks:
除了globalLocks,還有另一個名額locks同樣負責描述資料庫中鎖的情況。大家會注意到在一些子名額中會有大寫的”W,R”與小寫的”w,r”。在這裡,小寫的r與w均為意向鎖的意思,MongoDB的意向鎖更像樂觀鎖,即雖然使用了鎖但事實上并沒有鎖住資料。而我們真正需要關注的是大寫的W與R,它們均為排它鎖,它們的值也是累計值,通過它們每秒的增值,我們可以判斷出我們系統的健康狀況及業務通路的合理程度。子名額oplog的鎖在從庫上表現非常明顯,當我們的從庫觸發apply oplog時,它會對oplog進行加鎖。oplog是一個全局鎖,當長時間觸發時,會影響從庫的讀取,大家盡量保持主從庫之間延遲處在較小的水準,反過來說當我們的從庫讀請求變慢時,我們也可以參考這個值判斷是否是主從庫延遲過大的問題。
5.
network:
network是一個記錄網絡流量的累計值。bytesIn與bytesOut分别表示網絡進口與網絡出口流量,這些資料均已在MongoDB端被統計,physicalBytesIn與physicalBytesOut是3.4版本新加的名額,表示壓縮後即實體實際進口流量及實體即壓縮後出⼝流量。
6.
opcounters:
opcounters是大家在使用過程中會經常參考的名額,是一個比較經典的監控名額 ,opcounters即為Op本身的一些QPS,其中command表示除了delete,getmore,insert,query,update以外,其他所有的操作指令,比如執行ServerStatus等這樣一些操作,這個值也是累計值,我們通過采集它每秒的增量并将它們加和可以得到它真實的QPS,它的最大值是2的30次方,當系統運作時間過長該值超過2的30次方時,它會置為0值。大家有時會有這樣的疑問:“為什麼有時系統在某一時刻大量的逾時,但QPS卻并不高?”這是因為MongoDB的統計都是在操作執⾏完成之後才會生成,如果此時使用者的操作在MongoDB内部被鎖住的話,這就造成了業務之間的時間差使得在這段時間内QPS不會增高,反而降低。
7.
mem:
mem名額描述的大多數是記憶體中的狀态。bits表示目前的MongoDB由多少位編譯而成。resident表示常駐實體記憶體的大小,機關是兆。mem中的名額均為目前的值,大家取出來可以直接使用。
8.
metrics:
metrics中的名額較多,而且不統一。metrics|command的名額大體可分為兩類:metrics|command|failed記錄了指令失敗的總次數,metrics|command|total記錄了指令執行的總次數,我們用total每秒的內插補點即可求得每秒執行指令的總次數。與前面講的opcounters|command結合來看我們就可知道在一段時間内資料庫中哪些指令執行的次數較多。下面的metrics|document|delete等名額為對檔案的修改操作次數,也為累計值,同opcounters中的名額一樣,也是在操作執⾏結束後才會記錄。metrics|getLastError這類名額也是累計值,主要是在write大于1的模式下會使用到。其中metrics|getLastError|wtime|num名額表示寫操作在w>1模式下getLastError需要等待其它節點應答的次數,metrics|getLastError|wtime|totalMillis表示寫操作在w>1模式下getLastError需要等待其它節點應答的總時間,當這兩個名額的除值即totalMillis/num的值過高時,說明平均寫入同步延遲的時間過長,造成這種狀态的原因可能是因為從結點的性能出現問題,導緻整個叢集性能的下降。
9.
wiredTiger:
wiredTiger|cache|maximum
bytes configured用來配置cache大小的名額,wiredTiger|cache|bytes currently in the cache表示目前cache使用大小的名額,二者相除,即可得到cache的使用率,tracked dirty bytes in the cache表示目前髒頁大小,即我們寫入或落盤的cache大小,寫入大,如果是常态,可以适當提高dirty trigger。bytes read into cache與bytes written from cache名額是cache的讀寫量,它們的高低一般展現在我們磁盤的io讀與io寫上。concurrentTransactions是一個很有趣的名額,不知道大家平時是否有注意過?這個名額表示的是wiredTiger本身transaction控制的數量,這個值預設的是128個,當有一個請求時,會耗用一個transaction,在請求結束時,被耗用的值會被加回,當所有128個值被耗用光時,則從MongoDB層到所有引擎層的請求均會被block住,這些請求隻有wiredTiger将持有的transaction釋放掉時才會被執行。transaction checkpoint total time 名額也是一個累計值,它會在checkpoint結束之後才會進行計算該值,我們可以通過這個值計算checkpoint開始時間,并檢查是否與系統發生問題的時間吻合。
<b>三.場景診斷:</b>
介紹了以上這麼多名額,我們下面在使用場景中來看看它們是怎麼應用的。
當我們的用戶端報錯:client checkout connect timeout時
這種情況⼀般是用戶端沒有釋放連結或者沒有用連接配接池技術導緻的,這時我們往往要看服務端與應用端的連接配接池情況。對于應用端來說,我們要關注connection.avaliable這個名額是否曾經出現過跌至0的情況,如上圖所示,這是一張秒級監控圖,在圖中我們會發現雖然多數時間内avaliable名額會升滿,但是有時該值還是會跌為0,在跌0的點,就一定會出現timeout的報錯。通過這個名額的異常,我們可以采取在應用端使用一些連接配接池技術或檢查一下是否存在連接配接沒有釋放等措施來進行一些優化。
2. 寫入不斷逾時:
寫入不斷逾時的情況是一個比較常見比較經典的情況了。當出現這種問題時,我們會發現我們資料庫中的cache usage名額會不斷飙高,有時也會出現transactions名額跌0的現象出現,此時明顯我們的讀寫操作已無法繼續執行。
<b>四.總結</b>
以上即為MongoDB中重要監控名額的解讀及應用,通過這些名額我們可以比較快地确定我們業務中出現的問題,希望大家在使用MongoDB的過程中對這些名額有所重視。