是什麼造成了資料庫的卡頓

2022-01-29 13:32:09 字數 3768 閱讀 1760

目錄

三、找出元凶

四、解決思路

宣告:本文同步發表於 mongodb 中文社群,傳送門:

mongodb 提供了非常強大的效能分析及監控的命令,諸如 mongostat、mongotop 可以讓我們對資料庫的執行態效能瞭如指掌。

然而,這次我們在效能環境上就遇到乙個非常棘手的問題:

某服務介面在 1-5分鐘內偶現超時導致業務失敗!

在介面呼叫上返回超時屬於前端的判斷,通常是設定的乙個閾值(比如 3s)。

由於問題是偶現,且沒辦法發現有明顯的規律,很難直接判斷出原因。

而平台在做了微服務拆分之後,問題定位的難度加大了不少,且當前的呼叫鏈功能也不夠完善。

業務診斷

在一番分析後,梳理出介面呼叫的關係圖如下:

其中,服務a 通過 rpc呼叫服務b的介面,而服務b 又通過 mongodb 進行資料讀寫。

mongomanager 是 用於管理 mongodb 的乙個**服務,主要是實現一些資料備份、監控的任務。

在採集了一些資料之後,我們基本把問題範圍鎖定到了 mongodb 資料庫上面,這些手段包括:

從介面監控及 wiredshark 抓包結果中確認到,db 操作的響應時間都出現了偶現的超長(3s以上)。

而通過 commandlistener 將慢操作輸出統計後,得到的圖表如下:

其中典型的慢操作語句如:

query:

update: }

然而,這些慢操作並沒有明顯的問題嫌疑,除了以寫操作為主之外,索引的命中也沒有問題。

資料庫診斷

接下來,我們將焦點集中到了資料庫上,檢查了 cpu、記憶體、網路、磁碟這些常規指標後並沒有發現什麼異常。

通過mongostat觀察到的如下圖:

圖- mongostat

其中的乙個異常點是netout 會有偶現的積壓情況

然後是嘗試通過db.currentop()這個命令來看看能不能揪出慢操作背後的元凶。

currentop 還是比較好用的,尤其是在定位一些長時間慢操作問題上

然而,我的想法落空了,這個辦法並沒有任何發現! 因為問題屬於偶現,所以執行currentop 需要一些好的運氣..

儘管如此,我們還是大概能判定,在出現慢操作的時候,資料庫出現了命令積壓(卡頓)的情況

"可能存在某個定時器的鎖,對業務操作產生了阻塞!"

那麼,鎖從**來? 我們將目光移向了 mongomanager,的確這個程式承載了許多管理上的功能,包括監控、備份、公升級這些瑣事..

其中,執行資料庫資訊採集的監控定時器存在最大的嫌疑!,那麼問題又來了,

"如果是定時器導致的卡頓,為什麼慢操作卻沒有定時產生的規律呢?"

這個問題在前面也對我們產生了很大的困擾,但乙個比較合理的解釋是:

"mongomanager 是多節點的,而其中定時器是按照 時間間隔來運作的,而不是整點觸發。"

這樣就能解釋,為什麼慢操作通常都是在1-5分鐘內不規律的出現了。

為了證實這個想法,我們直接將 mongomanager 逐個關閉到僅剩下乙個,最終通過commandlistener收集到的慢操作圖表如下:

看,這次的慢操作非常的規律,基本每5分鐘就會出現一次卡頓!

然後我們將全部的 mongomanager 關閉,業務的慢操作完全消失了。

經過前面的問題定位,我們已經能確定是mongomanager的定時器搞的鬼了。

接下來走讀**,發現有下面這樣的一段實現:

public void testdboperation() 

if (allcollections.isempty())

//test a random collection

string randomcollection = allcollections.get((int) (allcollections.size() * math.random()));

//issue find operation

database.getcollection(randomcollection).find().first();

} catch (exception e)

}

為了便於理解,上述的**做了比較多的簡化,大致的步驟是:

上述的**由定時器在5分鐘觸發一次,跟出現慢操作的條件是吻合的。

其中 listcollections 會獲取到乙個集合的列表,我們猜測,這個操作可能會阻塞資料庫的操作。

通過搜尋官方文件,我們發現該操作使用了乙個共享讀鎖(s):

圖-listcollection鎖

mongodb 鎖機制

為了說明阻塞的產生,這裡需要解釋下mongodb的鎖機制:

在資料庫內部有下面這幾種鎖:

意向鎖提供了資料庫系統的"多粒度鎖"的能力,是提公升併發能力的關鍵手段, wiredtiger 也是基於此來實現行級鎖的。

幾種鎖的互斥關係如下表所示:

鎖型別sxis

ixstf

tfxf

fffis

tftt

ixfft

t基於此,我們可以得出這樣的結論:

由定時器產生 的 listcollections 操作會對資料庫產生讀鎖(s),從而對文件寫操作(資料庫的意向寫鎖ix)產生了阻塞。

那麼,listcollections 從監控的意義上來看是不應該對資料庫產生阻塞的。

我們認為這應該是mongodb 3.4版本乙個bug,而server-34243 這裡提交的乙個issue已經得到解決。

在最新的 4.x版本文件中,可以發現 listcollections 的許可權已經變更成了 意向讀鎖(is)。

通過 4.0 版本的 releasenotes 可以確認這點:

the command listcollections takes intent shared lock on the database. 

in previous versions, the command takes shared lock on the database.

在了解了事情的來龍去脈之後,我們可以確定這是 mongodb 3.4 版本的乙個不嚴謹的實現導致的問題。

由於無法直接公升級整個資料庫版本(代價太大), 我們在監控程式上做了優化,即將 listcollections 結果進行了快取,避免定時器每次都去操作這個命令,而問題最終得到了解決。

"監控不是銀彈,濫用也會有坑",至少從這次的事件中,我們得到了乙個教訓!

而要在這個問題上舉一反三的話,那就是需要警惕一些資料庫操作潛在的鎖問題了,比如:

以上的這些事情,你 get 到了嗎?

是什麼造成了資料庫的卡頓

目錄 宣告 本文同步發表於 mongodb 中文社群,傳送門 mongodb 提供了非常強大的效能分析及監控的命令,諸如 mongostat mongotop 可以讓我們對 資料庫的執行態效能瞭如指掌。然而,這次我們在效能環境上就遇到乙個非常棘手的問題 某服務介面在 1 5分鐘內偶現超時導致業務失敗...

是什麼造成了資料庫的卡頓

目錄 比奇 網 mongodb 提供了非常強大的效能分析及監控的命令,諸如 mongostat mongotop 可以讓我們對資料庫的執行態效能瞭如指掌。然而,這次我們在效能環境上就遇到乙個非常棘手的問題 某服務介面在 1 5分鐘內偶現超時導致業務失敗!在介面呼叫上返回超時屬於前端的判斷,通常是設定...

是什麼造成了資料庫的卡頓

目錄宣告 本文同步發表於 mongodb 中文社群,傳送門 mongodb 提供了非常強大的效能分析及監控的命令,諸如 mongostat mongotop 可以讓我們對資料庫的執行態效能瞭如指掌。然而,這次我們在效能環境上就遇到乙個非常棘手的問題 某服務介面在 1 5分鐘內偶現超時導致業務失敗!在...