讀古今文學網 > MongoDB實戰 > 10.2 監控與診斷 >

10.2 監控與診斷

在生產環境中部署完MongoDB,你就希望能瞭解它的運轉情況。如果系統性能在慢慢下降或者經常發生故障,你希望能夠知道這些情況,這就該用到監控了。讓我們先從最簡單的監控開始:日誌。隨後我們會看一些內置命令,它們能提供正在運行的MongoDB服務器的大多數信息;這些命令是mongostat工具和Web控制台的基礎,我會對mongostat工具和Web控制台做個簡要說明。我還會推薦幾個外部監控工具。本節最後會介紹兩個診斷工具:bsondumpmongosniff

10.2.1 日誌

日誌是第一級監控,正因如此,你應該計劃保留所有部署的MongoDB的日誌。1通常這都不是問題,因為MongoDB在後台運行時要求你指定--logpath選項。此外,還有一些需要留意的額外設置。要開啟詳細日誌(verbose logging),在啟動mongod進程時加上-vvvvv選項(v越多,輸出越詳細)。舉例來說,如果需要調試一些代碼,想要在日誌裡記錄下每個查詢,這就很方便。但是也要注意,詳細日誌會讓日誌文件變得很大,可能會影響服務器的性能。

1. 不要簡單地通過管道將日誌輸出到/dev/nullstdout

其次,可以在啟動mongod時使用--logappend選項,這會讓日誌追加到現有日誌文件後面,而非覆蓋它。

最後,如果有一個長時間運行的MongoDB進程,你可能想寫一個腳本週期性地滾動日誌文件,為此,MongoDB提供了logrotate命令,可以像這樣在Shell裡運行該命令:

> use admin
> db.runCommand({logrotate: 1})
  

向進程發送SIGUSR1信號也能運行logrotate命令,下面是如何向進程號為12345的進程發送SIGUSR1信號:

$ kill -SIGUSR1 12345
  

10.2.2 監控工具

本節我會介紹MongoDB自帶的監控命令和工具。

1. 數據庫命令

有三個展示MongoDB內部狀態的數據庫命令,它們是所有MongoDB監控應用程序的基礎。

  • serverStatus

serverStatus命令的輸出真是名副其實的內容豐富。統計的所有信息當中包含頁錯誤、B樹訪問率、打開連接數,以及總的插入、更新、查詢和刪除。下面是一段節選後的serverStatus命令輸出:

> use admin
> db.runCommand({serverStatus: 1})
{
  \"host\" : \"ubuntu\",
  \"version\" : \"1.8.0\",
  \"process\" : \"mongod\",
  \"uptime\" : 246562,
  \"localTime\" : ISODate(\"2011-03-13T17:01:37.189Z\"),

  \"globalLock\" : {
    \"totalTime\" : 246561699894,
    \"lockTime\" : 243,
    \"ratio\" : 9.855545289656455e-10,
    \"currentQueue\" : {
      \"total\" : 0,
      \"readers\" : 0,
      \"writers\" : 0
    },
  },
  \"mem\" : {
    \"bits\" : 64,
    \"resident\" : 3580,
    \"virtual\" : 9000,
    \"mapped\" : 6591
  }
  \"ok\" : 1 }
  

globalLock部分很重要,因為它揭示了服務器花在寫鎖上的總時間。這裡的高比例說明寫操作有瓶頸。currentQueue也許是更具體的瓶頸表述,如果有大量的讀或寫等在隊列裡,那麼就該進行某種優化了。

mem部分顯示了mongod進程是如何使用內存的。bits字段說明這是一台64位的機器。resident是MongoDB所佔用的物理內存數量。virtual是進程所映射的虛擬內存的兆字節數,mappedvirtual的子集,標明那些內存裡有多少是只用來映射數據文件的。本例中,有大約6.5 GB的數據文件被映射到了虛擬內存裡,其中3.5 GB是物理內存。我反覆強調,理想情況下工作集應該能被放到內存裡,mem部分能提供一個大概的信息,說明情況是否如此。

每個版本的MongoDB裡,serverStatus的輸出都會有所變化並得以改進,因此像本書這樣在非永久性媒介裡為該命令編寫文檔並不總是很有幫助。你可以在http://www.mongodb.org/display/DOCS/serverStatus看到該命令的最新詳細說明。

  • top

top命令會顯示每個數據庫的操作計數器。如果應用程序使用了多個物理數據庫,或者你想看看操作的平均耗時,那麼這是個有用的命令。下面是一些示例輸出:

> use admin
> db.runCommand({top: 1}) {
\"totals\" : { \"cloud-docs\" :
{ \"total \" : { \"time\" : 194470, \"count\" : 20 },
  \"readLock\" : { \"time\" : 324, \"count\" : 12 },
  \"writeLock\" : { \"time\" : 194146, \"count\":8},
  \"queries \" : { \"time\" : 194470, \"count\" : 20 },
  \"getmore \" : { \"time\" : 0, \"count\":0}},
\"ok\" : 1}
  

此處可以看到很多時間都花在了寫鎖上,值得深入調查一下,看看寫操作是否有可以優化的地方。

  • db.currentOp

能知道MongoDB目前正在做什麼常常很有用,db.currentOp方法就能揭示這個信息,它會返回當前正在運行的所有操作,以及正在等待運行的其他操作。下面是該方法的輸出示例,它是在上一章裡配置的分片集群上運行的:

db.currentOp
[{
      \"opid\" : \"shard-1-test-rs:1232866\",
      \"active\" : true,
      \"lockType\" : \"read\",
      \"waitingForLock\" : false,
      \"secs_running\" : 11,
      \"op\" : \"query\",
      \"ns\" : \"docs.foo\",
      \"query\" : {
        \"$where\" : \"this.n > 1000\"
      },
      \"client_s\" : \"127.0.0.1:38068\",
      \"desc\" : \"conn\"
    }]
  

現在正在執行一條特別慢的查詢,可以看到它已經運行了11 s了,和所有查詢一樣,它會佔用讀鎖。如果這個操作有問題,你可能會想調查一下它的調用源,可以看看client字段。啊呀,這是一個分片集群,因此調用源是mongos進程,正如client_s字段名所標識的那樣。如果要殺掉這個操作,可以將opid傳給db.killOp方法:

db.killOp(\"shard-1-test-rs:1232866\")
{
  \"op\" : \"shard-1-test-rs:1233339\",
  \"shard\" : \"shard-1-test-rs\",
  \"shardid\" : 1233339
}
  

如果想要查看當前MongoDB服務器上正在運行的所有操作的列表,可以使用如下虛擬命令:

db[\'$cmd.sys.inprog\'].find({$all: 1})
  

2. mongostat

db.currentOp方法只會顯示特定時刻排在隊列中或者正在執行的操作。類似的,serverStatus命令只提供某一時間點上不同系統字段和計數器的快照。但是,有些時候你需要系統實時活動的視圖,這時就該mongostat登場了。mongostat效仿iostat和其他類似的工具,以固定時間間隔查詢服務器信息,顯示統計數據的矩陣,從每秒插入數到常駐內存量,再到B樹頁丟失頻率。

可以在localhost上調用mongostat命令,顯示信息每秒滾動一次:

  • $ mongostat

mongostat命令同樣也是高度可配置的,可以通過--help查看所有選項。它還有一個更出名的特性,即集群發現(cluster discovery);在啟動mongostat時帶上--discover選項,你可以將它指向單個節點,它會發現副本集或分片集群中的剩餘節點,隨後聚合顯示整個集群的統計信息。

3. Web控制台

通過Web控制台,你能以更可視化的方式獲得某個運行中的mongod進程的信息。每個mongod進程都會監聽服務器端口往上第1000個端口的HTTP請求。如果你的mongod運行在27017端口,那麼Web控制台就在28017端口。如果運行在localhost上,可以將Web瀏覽器指向http://localhost:28017,你會看到如圖10-1所示的頁面。

開啟服務器的基本REST接口後,還能獲得更多狀態信息。如果在啟動mongod時加上--rest,就能開啟很多額外的Web控制台命令,Web控制台的登錄頁面上有指向它們的鏈接。

圖10-1 MongoDB Web控制台

10.2.3 外部監控應用程序

大多數重要的部署都要求有外部監控應用,Nagios和Munin是兩款流行的開源監控系統,很多MongoDB部署都用它們來進行監控。兩款工具都只需安裝一個簡單的開源插件就能監控MongoDB。

編寫一個針對某款監控應用程序的插件並非難事,一般都涉及針對某個在線MongoDB數據庫運行不同統計命令。serverStatusdbstatscollstats命令通常就能提供需要的所有信息,你能直接通過HTTP REST接口獲得所有這些信息,不需要使用驅動。

10.2.4 診斷工具(mongosniffbsondump

MongoDB包含兩個診斷工具。第一個是mongosniff,它能偵聽客戶端發給MongoDB服務器的數據包並將其以易於理解的形式輸出。如果恰好要編寫一個驅動或是調試一個錯誤連接,那這就是最好的工具。可以像下面這樣啟動mongosniff,監聽本地網絡接口的默認端口:

sudo mongosniff --source NET I0
  

有客戶端(比方說MongoDB Shell)連接上來之後,你會得到一個簡單易讀的網絡交互情況:

127.0.0.1:58022 -->> 127.0.0.1:27017 test.$cmd 61 bytes
  id:89ac9c1d 2309790749 query: { isMaster: 1.0 } ntoreturn: -1
127.0.0.1:27017 <<-- 127.0.0.1:58022 87 bytes
  reply n:1 cursorId : 0 { ismaster: true, ok: 1.0 }
 

通過--help可以看到mongosniff的所有選項。

另一個有用的工具是bsondump,允許你查看原始BSON文件。BSON文件是由mongodump工具(稍後會討論它)和副本集回滾來生成的。2舉例來說,假設你導出了一個只有單個文檔的集合。如果那個集合最終被放到一個名為users.bson的文件裡,那麼可以輕鬆地用如下命令查看文件內容:

2. 還有其他一些情況下你也會看到原始BSON文件,但是MongoDB的數據文件並非其中之一,所以不要嘗試用bsondump查看它們。

$ bsondump users.bson
{ \"_id\" : ObjectId( \"4d82836dc3efdb9915012b91\" ), \"name\" : \"Kyle\" }
  

可以看到,bsondump默認將BSON輸出為JSON。如果正進行重要的調試工作,你需要查看真正的BSON類型構成及大小。為此,以調試模式運行工具:

$ bsondump --type=debug users.bson
--- new object ---
  size : 37
    _id
      type: 7 size: 17
    name
      type: 2 size: 15
  

該命令顯示了對象的總大小(37字節)、兩個字段的類型(7和2)以及那些字段的大小。