一.mongodb的監控php
mongostat是mongdb自帶的狀態檢測工具,在命令行下使用。它會間隔固定時間獲取mongodb的當前運行狀態,並輸出。若是你發現數據庫忽然變慢或者有其餘問題的話,你第一手的操做就考慮採用mongostat來查看mongo的狀態。html
它的輸出有如下幾列:sql
- inserts/s 每秒插入次數
- query/s 每秒查詢次數
- update/s 每秒更新次數
- delete/s 每秒刪除次數
- getmore/s 每秒執行getmore次數
- command/s 每秒的命令數,比以上插入、查找、更新、刪除的綜合還多,還統計了別的命令
- flushs/s 每秒執行fsync將數據寫入硬盤的次數。
- mapped/s 全部的被mmap的數據量,單位是MB,
- vsize 虛擬內存使用量,單位MB
- res 物理內存使用量,單位MB
- faults/s 每秒訪問失敗數(只有Linux有),數據被交換出物理內存,放到swap。不要超過100,不然就是機器內存過小,形成頻繁swap寫入。此時要升級內存或者擴展
- locked % 被鎖的時間百分比,儘可能控制在50%如下吧
- idx miss % 索引不命中所佔百分比。若是過高的話就要考慮索引是否是少了
- q t|r|w 當Mongodb接收到太多的命令而數據庫被鎖住沒法執行完成,它會將命令加入隊列。這一欄顯示了總共、讀、寫3個隊列的長度,都爲0的話表示mongo毫無壓力。高併發時,通常隊列值會升高。
- conn 當前鏈接數
- time 時間戳
二.mongodb的優化mongodb
mongodb能夠經過profile來監控數據,進行優化。數據庫
查看當前是否開啓profile功能用命令性能優化
db.getProfilingLevel() 返回level等級,值爲0|1|2,分別表明意思:0表明關閉,1表明記錄慢命令,2表明所有併發
開始profile功能爲app
db.setProfilingLevel(level); #level等級,值同上nosql
level爲1的時候,慢命令默認值爲100ms,更改成db.setProfilingLevel(level,slowms)如db.setProfilingLevel(1,50)這樣就更改成50毫秒ide
經過db.system.profile.find() 查看當前的監控日誌。
如:
Js代碼
- > db.system.profile.find({millis:{$gt:500}})
- { 「ts」 : ISODate(「2011-07-23T02:50:13.941Z」), 「info」 : 「query order.order reslen:11022 nscanned:672230 \nquery: { status: 1.0 } nreturned:101 bytes:11006 640ms」, 「millis」 : 640 }
- { 「ts」 : ISODate(「2011-07-23T02:51:00.096Z」), 「info」 : 「query order.order reslen:11146 nscanned:672302 \nquery: { status: 1.0, user.uid: { $gt: 1663199.0 } } nreturned:101 bytes:11130 647ms」, 「millis」 : 647 }
這裏值的含義是
ts:命令執行時間
info:命令的內容
query:表明查詢
order.order: 表明查詢的庫與集合
reslen:返回的結果集大小,byte數
nscanned:掃描記錄數量
nquery:後面是查詢條件
nreturned:返回記錄數及用時
millis:所花時間
若是發現時間比較長,那麼就須要做優化。
好比nscanned數很大,或者接近記錄總數,那麼可能沒有用到索引查詢。
reslen很大,有可能返回不必的字段。
nreturned很大,那麼有可能查詢的時候沒有加限制。
官網:http://www.mongodb.org/display/DOCS/Database+Profiler
mongo能夠經過db.serverStatus()查看mongod的運行狀態
Js代碼
- > db.serverStatus()
- {
- 「host」 : 「baobao-laptop」,#主機名
- 「version」 : 「1.8.2」,#版本號
- 「process」 : 「mongod」,#進程名
- 「uptime」 : 15549,#運行時間
- 「uptimeEstimate」 : 15351,
- 「localTime」 : ISODate(「2011-07-23T06:07:31.220Z」),當前時間
- 「globalLock」 : {
- 「totalTime」 : 15548525410,#總運行時間(ns)
- 「lockTime」 : 89206633, #總的鎖時間(ns)
- 「ratio」 : 0.005737305027178137,#鎖比值
- 「currentQueue」 : {
- 「total」 : 0,#當前須要執行的隊列
- 「readers」 : 0,#讀隊列
- 「writers」 : 0#寫隊列
- },
- 「activeClients」 : {
- 「total」 : 0,#當前客戶端執行的連接數
- 「readers」 : 0,#讀連接數
- 「writers」 : 0#寫連接數
- }
- },
- 「mem」 : {#內存狀況
- 「bits」 : 32,#32位系統
- 「resident」 : 337,#佔有物理內存數
- 「virtual」 : 599,#佔有虛擬內存
- 「supported」 : true,#是否支持擴展內存
- 「mapped」 : 512
- },
- 「connections」 : {
- 「current」 : 2,#當前連接數
- 「available」 : 817#可用連接數
- },
- 「extra_info」 : {
- 「note」 : 「fields vary by platform」,
- 「heap_usage_bytes」 : 159008,#堆使用狀況字節
- 「page_faults」 : 907 #頁面故做
- },
- 「indexCounters」 : {
- 「btree」 : {
- 「accesses」 : 59963, #索引被訪問數
- 「hits」 : 59963, #因此命中數
- 「misses」 : 0,#索引誤差數
- 「resets」 : 0,#復位數
- 「missRatio」 : 0#未命中率
- }
- },
- 「backgroundFlushing」 : {
- 「flushes」 : 259, #刷新次數
- 「total_ms」 : 3395, #刷新總花費時長
- 「average_ms」 : 13.108108108108109, #平均時長
- 「last_ms」 : 1, #最後一次時長
- 「last_finished」 : ISODate(「2011-07-23T06:07:22.725Z」)#最後刷新時間
- },
- 「cursors」 : {
- 「totalOpen」 : 0,#打開遊標數
- 「clientCursors_size」 : 0,#客戶端遊標大小
- 「timedOut」 : 16#超時時間
- },
- 「network」 : {
- 「bytesIn」 : 285676177,#輸入數據(byte)
- 「bytesOut」 : 286564,#輸出數據(byte)
- 「numRequests」 : 2012348#請求數
- },
- 「opcounters」 : {
- 「insert」 : 2010000, #插入操做數
- 「query」 : 51,#查詢操做數
- 「update」 : 5,#更新操做數
- 「delete」 : 0,#刪除操做數
- 「getmore」 : 0,#獲取更多的操做數
- 「command」 : 148#其餘命令操做數
- },
- 「asserts」 : {#各個斷言的數量
- 「regular」 : 0,
- 「warning」 : 0,
- 「msg」 : 0,
- 「user」 : 2131,
- 「rollovers」 : 0
- },
- 「writeBacksQueued」 : false,
- 「ok」 : 1
- }
indexCounters:btree:misses 索引的不命中數,和hits的比例高就要考慮索引是否正確創建。
db.stats()查看某一個庫的原先情況
Java代碼
- > db.stats()
- {
- 「db」 : 「order」,#庫名
- 「collections」 : 4,#集合數
- 「objects」 : 2011622,#記錄數
- 「avgObjSize」 : 111.92214441878245,#每條記錄的平均值
- 「dataSize」 : 225145048,#記錄的總大小
- 「storageSize」 : 307323392,#預分配的存儲空間
- 「numExtents」 : 21,#事件數
- 「indexes」 : 1,#索引數
- 「indexSize」 : 74187744,#因此大小
- 「fileSize」 : 1056702464,#文件大小
- 「ok」 : 1
- }
查看集合記錄用
Java代碼
- > db.order.stats()
- {
- 「ns」 : 「order.order」,#命名空間
- 「count」 : 2010000,#記錄數
- 「size」 : 225039600,#大小
- 「avgObjSize」 : 111.96,
- 「storageSize」 : 307186944,
- 「numExtents」 : 18,
- 「nindexes」 : 1,
- 「lastExtentSize」 : 56089856,
- 「paddingFactor」 : 1,
- 「flags」 : 1,
- 「totalIndexSize」 : 74187744,
- 「indexSizes」 : {
- 「_id_」 : 74187744#索引爲_id_的索引大小
- },
- 「ok」 : 1
- }
mongostat命令查看運行中的實時統計,表示每秒實時執行的次數
mongodb還提供了一個機遇http的監控頁面,能夠訪問http://ip:28017來查看,這個頁面基本上是對上面的這些命令作了一下綜合,因此這裏不細述了。
二.mongodb的優化
根據上面這些監控手段,找到問題後,咱們能夠進行優化
上面找到了某一下慢的命令,如今咱們能夠經過執行計劃跟蹤一下,如
Java代碼
- > db.order.find({ 「status」: 1.0, 「user.uid」: { $gt: 2663199.0 } }).explain()
- {
- 「cursor」 : 「BasicCursor」,#遊標類型
- 「nscanned」 : 2010000,#掃描數量
- 「nscannedObjects」 : 2010000,#掃描對象
- 「n」 : 337800,#返回數據
- 「millis」 : 2838,#耗時
- 「nYields」 : 0,
- 「nChunkSkips」 : 0,
- 「isMultiKey」 : false,
- 「indexOnly」 : false,
- 「indexBounds」 : {#使用索引(這裏沒有)
- }
- }
對於這樣的,咱們能夠建立索引
能夠經過 db.collection.ensureIndex({「字段名」:1}) 來建立索引,1爲升序,-1爲降序,在已經有多數據的狀況下,可用後臺來執行,語句db.collection.ensureIndex({「字段 名」:1} , {backgroud:true})
獲取索引用db.collection.getIndexes() 查看
這裏咱們建立一個user.uid的索引 >db.order.ensureIndex({「user.uid」:1})
建立後從新執行
Java代碼
- db.order.find({ 「status」: 1.0, 「user.uid」: { $gt: 2663199.0 } }).explain()
- {
- 「cursor」 : 「BtreeCursor user.uid_1」,
- 「nscanned」 : 337800,
- 「nscannedObjects」 : 337800,
- 「n」 : 337800,
- 「millis」 : 1371,
- 「nYields」 : 0,
- 「nChunkSkips」 : 0,
- 「isMultiKey」 : false,
- 「indexOnly」 : false,
- 「indexBounds」 : {
- 「user.uid」 : [
- [
- 2663199,
- 1.7976931348623157e+308
- ]
- ]
- }
- }
掃描數量減小,速度提升。mongodb的索引設計相似與關係數據庫,按索引查找加快書讀,可是多了會對寫有壓力,因此這裏就再也不敘述了。
2.其餘優化能夠用hint強制索引查找,返回只是須要的數據,對數據分頁等。
db.currentOp()
Mongodb 的命令通常很快就完成,可是在一臺繁忙的機器或者有比較慢的命令時,你能夠經過db.currentOp()獲取當前正在執行的操做。
在沒有負載的機器上,該命令基本上都是返回空的
1
> db.currentOp()
2
{
"inprog"
: [ ] }
如下是一個有負載的機器上獲得的返回值樣例:
1
{
"opid"
:
"shard3:466404288"
,
"active"
:
false
,
"waitingForLock"
:
false
,
"op"
:
"query"
,
"ns"
:
"sd.usersEmails"
,
"query"
: { },
"client_s"
:
"10.121.13.8:34473"
,
"desc"
:
"conn"
},
字段名字都能自解釋。若是你發現一個操做太長,把數據庫卡死的話,能夠用這個命令殺死他
1
> db.killOp(
"shard3:466404288"
)