mongodb運維(3) db.currentOp與db.killOp命令
好久沒更新mongo運維這塊知識了,這次介紹 db.currentOp與db.killOp命令
數據庫優化方法有很多,但所有數據庫優化都離不開慢查詢優化。mysql、mongodb都可以開啟慢查詢,來對數據庫查詢進行分析。開啟慢查詢日志,對性能會有一定的影響。mongoDB
有時我們只想臨時看下慢查詢日志,應該如何處理。
這時,我們可以用到mongdb的db.currentOp
命令 ,他可以列出當前真正跑的op相關信息。
1.查看目前正在執行的所有查詢語句
db.currentOp();
2.查詢所有操作xxx集合並且執行時間已超過3s
的請求
db.currentOp( { "active" : true, "secs_running" : { "$gt" : 3 }, "ns" : /^xxx\./ } )
3. 當然,如果我當前db集群有非常多的集合,我也可以不限制xxx集合
db.currentOp( { "active" : true, "secs_running" : { "$gt" : 3 } } )
currentOp的過濾條件包括
-
請求操作類型,insert、update、delete…
-
請求對應的connectionId,threadId
-
請求是否正在等待鎖
-
請求執行時間
-
請求操作的DB或collection
-
請求query的內容
-
…等等
返回結果如下
{ "desc" : "conn44266", "threadId" : "140419266524928", "connectionId" : 44266, "client" : "10.10.68.209", "active" : true, "opid" : 4495651, "secs_running" : 25, "microsecs_running" : NumberLong(25459008), "op" : "command", "ns" : "xxxxx", "query" : { "count" : "c74dc2de71", "query" : { "video" : { "$exists" : true }, "_isdel" : 0, "deleted" : { "$ne" : true }, "verify" : { "$ne" : false } } }, "planSummary" : "IXSCAN { video: 1 }", "numYields" : 189, "locks" : { "Global" : "r", "Database" : "r", "Collection" : "r" }, "waitingForLock" : false, "lockStats" : { "Global" : { "acquireCount" : { "r" : NumberLong(380) } }, "Database" : { "acquireCount" : { "r" : NumberLong(190) } }, "Collection" : { "acquireCount" : { "r" : NumberLong(190) } } } }
結果
當我們知道某條語句是鎖庫的罪魁禍首的時候,我們就可以通過另一條語句,干掉對應的請求。
killOp 停止正在執行的查詢
用法:
db.killOp(opid)
目前Mongodb手冊,還未有一次清掉當前所有查詢,文檔地址:https://docs.mongodb.com/manual/reference/method/db.killOp/
執行后返回
{ "info" : "attempting to kill op", "ok" : 1 }
image.png
db.killOp(opid)的實現原理如下
每個連接對應的服務線程存儲了一個killPending的字段,當發送killOp時,會將該字段置1;請求在執行過程中,可以通過不斷的調用OperationContext::checkForInterrupt()來檢查killPending是否被設置,如果被設置,則線程退出。
一個請求要支持killOp,必須在請求的處理邏輯里加上checkForInterrupt()檢查點才行,否則即使發送了killOp,也只能等待請求完全處理完畢線程才會退出。
比如createIndex的處理邏輯里包含了類似如下的代碼,在createIndex的循環過程中,一旦killPending被置1了,createIndex的執行可以在當前循環結束時退出。
while (!createIndexFinished) { createIndexForOneElement(); checkForInterupt(); }
所以發送killOp后,請求要執行到下一個『檢查點』線程才會退出,MongoDB在很多可能耗時長的請求中,都加入了checkForInterrupt()檢查點,如創建索引,repair database,mapreduce、aggregation等。
批量一次清楚當前慢查詢
上面說還未有一次清掉當前所有查詢, 不過我們可以通過手動寫腳本實現。此腳本由diggzhang大神貢獻。文章鏈接:http://yangcongchufang.com/kill-mongo-ops.html
實現功能:傳入自己的IP地址,強制關停自己的異常查詢。
打開家目錄下的.mongorc.js
拷貝下面的killMyRunningOps
函數進去,重新打開mongoshell
即可加載這個函數(mongoshell
啟動時會預讀這個文件)。
~ cat ~/.mongorc.js
killMyRunningOps = function (clientIp) { var currOp = db.currentOp(); for (op in currOp.inprog) { if (clientIp == currOp.inprog[op].client.split(":")[0]) { db.killOp(currentOp.inprog[op].opid) } } }
用法很簡單,知道自己IP后,調用這個函數:
> killMyRunningOps("12.23.32.21") #####這個是客戶端的ip