淺嘗輒止MongoDB:管理(2)
目錄
四、驗證與修復
以下是一些資料已損壞的跡象:
- 資料庫伺服器無法啟動,表示資料檔案已損壞。
- 在伺服器日誌檔案中發現asserts或使用db.serverStatus()命令時發現asserts數目很大。
- 查詢結果很奇怪或出乎意料。
- 集合中的記錄數與預期不匹配。
任何一種跡象都可能表示應用出現了問題,或更麻煩的是,資料損壞或處於不一致狀態。
1. 修復伺服器
mongod --dbpath /data/db --repair
注意使用repair命令是一個代價很高的操作,它將花費很長時間,並要求使用兩倍於MongoDB資料檔案大小的空間,因為所有的資料都將被克隆到新的檔案並重建,這本質上是對所有資料檔案的重建。
一旦修復結束,就可以正常啟動伺服器,然後從備份中恢復任何丟失的資料。如果嘗試修復一個大型資料庫,那麼驅動器上的磁碟空間可能會不足,因為MongoDB需要在同一驅動器上建立資料庫的副本作為資料來源。為了處理這個問題,MongoDB修復工具提供了一個額外的命令列引數--repairPath。可以使用該引數指定一個具有足夠空間的驅動器用於儲存修復過程中建立的臨時檔案:
mongod -f /etc/mongodb.conf --repair --repairpath /mnt/bigdrive/tempdir
2. 驗證單個集合
> use test switched to db test > db.products.validate(); { "ns" : "test.products", "nInvalidDocuments" : NumberLong(0), "nrecords" : 3, "nIndexes" : 1, "keysPerIndex" : { "test.products.$_id_" : 3 }, "valid" : true, "warnings" : [ "Some checks omitted for speed. use {full:true} option to do more thorough scan." ], "errors" : [ ], "ok" : 1 } >
預設情況下,validate選項將同時檢查資料檔案和索引,並在操作完成之時提供集合的一些統計資訊。該選項將顯示資料檔案或索引中是否存在問題,但不會檢查所有文件的正確性。如果希望檢查所有文件,可以在函式呼叫時新增true引數即可:
> db.products.validate(true); { "ns" : "test.products", "nInvalidDocuments" : NumberLong(0), "nrecords" : 3, "nIndexes" : 1, "keysPerIndex" : { "test.products.$_id_" : 3 }, "indexDetails" : { "test.products.$_id_" : { "valid" : true } }, "valid" : true, "warnings" : [ ], "errors" : [ ], "ok" : 1 } >
也可以使用validate選項只驗證索引:
> db.runCommand({validate:"products", scandata:false});
{
"ns" : "test.products",
"nInvalidDocuments" : NumberLong(0),
"nrecords" : 3,
"nIndexes" : 1,
"keysPerIndex" : {
"test.products.$_id_" : 3
},
"valid" : true,
"warnings" : [
"Some checks omitted for speed. use {full:true} option to do more thorough scan."
],
"errors" : [ ],
"ok" : 1
}
>
3. 修復集合驗證錯誤
如果在驗證集合的過程中出現錯誤(顯示在驗證文件的errors部分),有幾種方式可以修復資料(注意一定要對備份資料)。在恢復備份之前,應該先檢視MongoDB例項的日誌,檢查是否存在任何關於該錯誤的相關資訊;如果有,則該資訊將提示下一個需要完成的步驟。
(1)修復索引 如果驗證結果顯示索引是損壞的,那麼可以重建受影響集合的索引:
> db.products.reIndex();
{
"nIndexesWas" : 1,
"nIndexes" : 1,
"indexes" : [
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.products"
}
],
"ok" : 1
}
>
MongoDB將會刪除集合中目前的所有索引,然後重建它們。如果使用了資料庫的repair選項,也將在資料庫的所有集合中執行reIndex()函式。
(2)修復資料檔案 修復所有資料檔案的最好也是最危險的方式是:使用伺服器的--repair選項或db.repairDatabase()命令。後者將修復單個數據庫中的所有集合檔案,然後重建所有已定義的索引。
> use test;
switched to db test
> db.repairDatabase();
{ "ok" : 1 }
>
repairDatabase()不適合在線上伺服器上執行,因為它在重建資料檔案時會阻塞對資料的所有請求。這將導致資料庫修復過程中的所有讀寫操作都被阻塞。
MongoDB的修復功能是一個強力選項。它嘗試修復並重建資料結構和索引,這通過從磁碟讀取並重建整個資料結構的方式來完成。如果可能,應該嘗試從備份檔案恢復;repairDatabase()只應被用作最後的解決方案。
4. 壓縮集合的資料檔案
> use test;
switched to db test
> db.runCommand({compact:"products"});
{ "ok" : 1 }
>
命令compact會在已有資料檔案中為指定的集合整理並重組資料結構,使用預設的WiredTiger儲存引擎會恢復磁碟空間,但對於老的MMAPv1儲存引擎,不會釋放磁碟空間。
五、監控
1. 檢視伺服器狀態
db.serverStatus();
輸出中可以看到MongoDB的版本、後臺刷寫情況、副本集情況、運算元量情況、進出網路情況、連線數情況和記憶體情況等資訊。其中記憶體相關欄位的含義是(單位是M):
- mapped:對映到記憶體的資料大小
- visze:佔用的虛擬記憶體大小
- res:實際使用的記憶體大小
serverStatus輸出了很多細節,在該函式的輸出資訊中可以找到兩個最重要的部分:opcounters和asserts。
opcounters部分顯示了資料庫伺服器上已經執行的每種操作的數目。對於特定應用,應該知道這些計數器的正常情況。如果這些計數器開始偏離正常的比例,那麼可能就是早期的警告:應用中出現了問題。
asserts部分展示了伺服器和客戶端丟擲異常或警告的數目。如果異常或警告的數目迅速增加,那麼最好檢視伺服器的日誌檔案,以檢查是否系統出現了問題。大量的斷言也可能表示資料庫中出現了問題,應該檢查MongoDB例項的日誌檔案,以確認這些斷言是否屬於普通的使用者斷言,如重複鍵值衝突等等問題。
也可以通過mongostat來檢視:
mongostat -u wxy --authenticationDatabase admin
mongostat提供MongoDB伺服器當前狀態的概覽,例如,將顯示出資料庫操作的執行頻率、索引的命中率以及應用等待資料庫釋放鎖所耗費的時間。最有用的主要資料列是前6列,它們將顯示出mongod伺服器處理特定操作的速率。在分析問題時,值得關注的其它列還有:
- faults:查詢從磁碟讀取資料,標誌伺服器未達到最佳,所需的資料並未完全儲存找記憶體中。
- qr/qw:佇列等待的數目。因為MongoDB支援一個寫入器(插入、更新和刪除)和多個讀取器(查詢),這可能導致出現讀取查詢被表現不佳的寫操作阻塞的情況。更糟糕的是,可能出現許多讀/寫操作同時被一個性能不佳的寫操作阻塞的情況。檢查是否存在某個查詢阻塞了其它查詢的執行。
- ar/aw:活動客戶端的數目。
- conn:開啟的連線數。
- flushes:資料刷寫到磁碟的數目。
- vsize:使用虛擬記憶體大小。
- mapped:隱射的記憶體大小,約等於資料目錄大小。
2. 檢視命令列引數
> db.serverCmdLineOpts();
{
"argv" : [
"mongod",
"-f",
"/home/mongodb/mongodb-4.0.2/mongodb.conf"
],
"parsed" : {
"config" : "/home/mongodb/mongodb-4.0.2/mongodb.conf",
"net" : {
"bindIpAll" : true
},
"processManagement" : {
"pidFilePath" : "/home/mongodb/mongodb-4.0.2/data/mongodb.pid"
},
"security" : {
"authorization" : "enabled"
},
"storage" : {
"dbPath" : "/home/mongodb/mongodb-4.0.2/data/"
},
"systemLog" : {
"destination" : "file",
"path" : "/home/mongodb/mongodb-4.0.2/data/mongodb.log"
}
},
"ok" : 1
}
>
3. 檢視資料庫/表狀態
db.stats(1024*1024);
返回資料庫的名稱,集合數量,索引數量、大小,資料檔案大小,儲存空間大小和物理檔案大小,以MB為單位。
db.collection.stats(1024*1024);
4. 檢視當前Query執行情況
db.currentOP();
檢視當前執行的程序,類似MySQL的show processlist。可以新增過濾條件:
db.currentOP({"ns":"test"});
5. 監控MongoDB狀態
mongotop -u wxy --authenticationDatabase admin
檢視哪些物件最繁忙。
mongostat -u wxy --authenticationDatabase admin
insert、query、update、delete、getmore、command表示每種對應操作的發生次數。其中faults表示訪問失敗數,資料從記憶體交換出去,放到swap。值越小越好,最好不要大於100。
- flushes:表示刷寫到磁碟的次數。
- mapped:表示對映到記憶體的數量,約等於資料目錄大小。
- vsize:表示正在使用的虛擬記憶體大小,通常為資料目錄的2倍。(一次用於對映,一次用於日誌系統)
- res:表示正在使用的記憶體大小。
- qr|qw:表示讀寫操作佇列大小,即有多少讀寫操作被阻塞,等待進行處理。
- ar|aw:表示活動客戶端的數量,即正在進行讀寫操作的客戶端。
- netId:表示通過網路傳輸進來的位元組數。
- netou:t表示通過網路傳輸出的位元組數。
- Conn:表示伺服器開啟的連線數。
- time:表示統計的時間。
六、其它常見任務
1. 啟動伺服器
mongod -f /home/mongodb/mongodb-4.0.2/mongodb.conf &
2. 獲取伺服器版本
use admin;
db.version();
3. 關閉伺服器
use admin
db.shutdownServer()
當且僅當伺服器不響應上面方法時,使用下面的命令停止伺服器:
sudo killall -15 mongod
4. 輪換日誌檔案
use admin;
db.adminCommand({"logRotate":1});
這個命令類似與MySQL的flush log,它告訴MongoDB開始編寫一個新的日誌檔案,用轉換它時的時間戳重新命名現有檔案。之後這些舊檔案可以安全的刪除。還可以指導MongoDB轉換日誌,不需要使用如下的SIGUSR1訊號連線例項:
kill -SIGUSR1 `pidof mongod`
5. 刷寫並鎖
> db.fsyncLock() # 刷寫到磁碟,並鎖住資料庫。此時資料庫只能讀,不能寫。保證了資料的一致性,在此可以進行復制檔案或快照備份。
{
"info" : "now locked against writes, use db.fsyncUnlock() to unlock",
"lockCount" : NumberLong(1),
"seeAlso" : "http://dochub.mongodb.org/core/fsynccommand",
"ok" : 1
}
> db.currentOP() # 檢視鎖情況
{
"inprog" : [
...
],
"fsyncLock" : true, # MongoDB的fsync程序(負責將修改寫入磁碟)正在阻塞寫入操作
"info" : "use db.fsyncUnlock() to terminate the fsync write/snapshot lock",
"ok" : 1
}
> db.fsyncUnlock() # 解鎖
{ "info" : "fsyncUnlock completed", "lockCount" : NumberLong(0), "ok" : 1 }
> db.currentOP()
{
"inprog" : [
{
"host" : "hdp4:27017",
"desc" : "conn133",
"connectionId" : 133,
"client" : "127.0.0.1:22844",
"appName" : "MongoDB Shell",
"clientMetadata" : {
"application" : {
"name" : "MongoDB Shell"
},
"driver" : {
"name" : "MongoDB Internal Client",
"version" : "4.0.2"
},
"os" : {
"type" : "Linux",
"name" : "CentOS Linux release 7.2.1511 (Core) ",
"architecture" : "x86_64",
"version" : "Kernel 3.10.0-327.el7.x86_64"
}
},
"active" : true,
"currentOpTime" : "2018-10-10T14:03:49.298+0800",
"opid" : 1625425,
"lsid" : {
"id" : UUID("c15d93d9-d9f6-456e-8806-8d2f29dde493"),
"uid" : BinData(0,"d+J7nEzLLc6L5Ue/Mq/KRu3nBl6vz3nsX18GjKuwhYs=")
},
"secs_running" : NumberLong(0),
"microsecs_running" : NumberLong(359),
"op" : "command",
"ns" : "admin.$cmd.aggregate",
"command" : {
"currentOp" : 1,
"lsid" : {
"id" : UUID("c15d93d9-d9f6-456e-8806-8d2f29dde493")
},
"$db" : "admin"
},
"numYields" : 0,
"locks" : {
},
"waitingForLock" : false,
"lockStats" : {
}
}
],
"ok" : 1
}
>
6. 升級MongoDB
升級資料庫伺服器的必須步驟如下:
- 備份資料並保證備份可用。如果可能,將備份資料恢復到另一個伺服器,確認備份是正確的。
- 停止應用,或者將它轉移到另一臺伺服器。
- 停止MongoDB伺服器。
- 升級MongoDB伺服器的程式碼至目標版本。
- 使用mongo shell對資料集進行初始的完整性檢測。
- 只要有任何地方看起來可能有問題,就使用驗證工具檢查資料。
- 完成所有的檢查之後,重新啟動應用。
- 在重新開啟服務或者將流量轉移回當前伺服器時,對應用認真進行測試。
使用複製集的最大特點之一就是:可用於執行滾動升級。該方法被設計用於減小潛在的宕機時間和一些MongoDB大改動(例如升級)所造成的影響。除了下面列出的流程,還應該建立備份並在非生產環境中進行測試。一旦完成詳細的調查並保證系統是可恢復的,就可以按照下面的流程進行滾動升級:
- 一次停止一臺備庫進行升級。
- 在主庫上執行rs.stepDown()命令。已經升級成功的某臺備庫將變成主庫。
- 升級原主庫。