一次mongo查詢不存在欄位引發的事故

希希大隊長發表於2021-01-05

  話說今天的一個小小的查詢失誤給了我比較深刻的教訓,也讓我對mongo有了更深刻的理解,下面我們來說說這個事情的原委:

我們經常使用阿里雲子賬號在DMS上查詢線上資料庫資料,今天也是平常的一次操作

集合:

XXXX_message
資料量約 600萬

我執行了下面的mongo查詢:

db.XXXX_message.find({"channel_id": "1000000009XXXX700XXXX"}).limit(20);

但是上述語句中的 "channel_id" 欄位不存在,真實欄位應該是channel(有索引),屬於失誤操作

在執行過程中,我發現查詢時間很久,於是中斷了查詢又重試了兩次,還是很久,最後中斷了查詢,我意識到我想查的欄位可能錯了,於是看了下集合索引,使用正確的欄位檢索得到結果

但就在這時候,一場事故也在悄然醞釀,2分鐘後,阿里雲監控中心打來告警電話,mongo資料庫cpu、iops異常升高

 

 

起初並沒有意識到是這個查詢導致的,還以為是半小時前釋出的版本可能有問題,於是立即回滾了版本並開始專案檢查

查了許久,並沒有查到可能造成本次資料庫異常告警的原因,專案對該庫的依賴的操作的地方非常少。

當我們苦苦想不到原因的時候,我們去查了下相關慢sql日誌,果然一道耗時約1800000ms的慢sql日誌引起了我們的注意

這時候我似乎意識到了點什麼,我立馬查阿里雲控制檯查詢歷史核對了我剛才查詢的時間和資料庫cpu、磁碟iops異常升高的時間節點

完全對上了,該起事故持續半小時左右,那條沒有被成功中斷的sql也執行了半小時左右

 

 

這讓我很震驚,一次控制檯查詢居然導致整個資料庫出現如此嚴重的問題,mongo底層沒有考慮過不存在欄位查詢問題嗎?

我慢慢平復心情,仔細回顧這件事情,我嘗試著從mongo和mysql的底層去理解這個問題

mongo本身是集合型資料庫,意味著每個集合文件都可以有自己獨立的資料結構,和mysql等關係型資料庫的很重要的區別就是它沒有固定的表結構,它包容且隨性

當在查詢一個不存在的欄位的時候,它仍然按照普通查詢檢索資料,這時候它會全表掃描,也就是說在上述失誤語句中,mongo底層檢索了整個集合的資料集,

遍歷了該集合所有的磁碟塊,這才導致磁碟iops升高且cpu升高。

這次經歷讓我覺得我有必要記錄下相關心得,可能對於很多高階技術人員,這些東西都是很容易理解和規避的事情,但大多數人對此可能並沒有深刻認識

這次事故讓我對技術多了一層敬畏,這有助於我在今後的程式碼實踐和操作中更加謹慎和多一層思考,希望大家以此為戒!

此文共勉!

 

相關文章