爲什麼要做這個案例分析?
因爲在其他同學已經找到問題代碼並修復後,我還沒有徹底弄明白下面這2個問題:
1.爲什麼是這段代碼導致的?
2.爲什麼看起來跟問題代碼無關的接口也受影響變得惡化,這段代碼到底是如何造成整個服務雪崩的?
在搞懂上面的一系列問題後,我認爲這是一次典型的慢查詢導致服務雪崩
案例(因爲沒有其他次要因素),沉澱總結下來,或許可以幫助我下次更快更準的找到排查思路,而不至於沒有方向浪費寶貴的排查時間,對於服務器問題線索的收集是有益的。
最容易獲得的問題信息
服務質量下降後,一般最快能夠獲取到的信息,就是服務接口響應監控信息,例如這一次:訪客服務API平均響應時長變慢,持續惡化,導致其他上游服務接口受影響
只要時間段選擇長一點,就會發現接口響應時間從平均200+ms逐漸惡化到1min+
如何找到出問題的接口
影響平均響應時長的,應該是一些耗時比較長的接口拉高的,但怎麼確認哪些接口是“罪魁禍首”,哪些接口是“受牽連”才惡化的?
在這個典型案例中,下面這兩個步驟可以確定目標:
1)拉長監控時間範圍,觀察服務有惡化端倪的時間點
例如這個案例中,我們發現問題的時間點約11:30,把監控時間段調爲11:00~12:00,不難觀察服務有惡化端倪的是11:10開始逐漸惡化
2)監控開始時間調整到開始惡化的時間(11:10),結束時間不變,查看接口列表,按時間正序排序
這樣做,主要是分析在服務開始惡化時,哪些接口已經出現問題了,而這部分接口往往就是主要問題甚至根本問題所在;順便可以看到,一些接口在服務開始惡化時本來響應良好,隨着時間增長不斷纔開始惡化的,這些往往都是“受牽連”的接口。
分析接口
本例中,接口線程分析顯示耗時發生在mongo查詢處。
解決的方式比較簡單,也不是討論的重點,一方面可以直接看看這段sql的語句是否有問題,另一方面可以通過數據庫慢查詢記錄看看具體慢的原因。
爲什麼其他接口會受牽連惡化
服務從11:10開始惡化,從mongo監控看主庫的CPU利用率有抖動
而從庫則問題比較明顯,CPU從11:10開始幾乎持續跑滿
再看看一個關鍵監控值:gl_cq_readers,其對應的應該是mongo命令db.serverStatus()
的"globalLock.currentQueue.readers"字段值,阿里雲對這個監控指標的解釋如下:
簡單來說,MongoDB中使用的是多粒度鎖,在加鎖時是一個層次性管理方式,從globalLock ===> DBLock ===> CollectionLock …,對於我們使用的WiredTiger引擎,讀寫併發時,使用的是文檔級別鎖。
這裏套用下阿里雲張友東的博客內容,
上述代碼⾥,如果holder不爲空,Client會先進去kQueuedReader或kQueuedWriter狀態,然後獲取⼀個ticket,獲取到
後轉換爲kActiveReader或kActiveWriter狀態。這⾥的ticket是什麼東⻄?
這⾥的ticket是引擎可以設置的⼀個限制。正常情況下,如果沒有鎖競爭,所有的讀寫請求都會被pass到引擎層,這樣
就有個問題,你請求到了引擎層⾯,還是得排隊執⾏,⽽且不同引擎處理能⼒肯定也不同,於是引擎層就可以通過設置
這個ticket,來限制⼀下傳到引擎層⾯的最⼤併發數。
wiredtiger設置了讀寫ticket均爲128,也就是說wiredtiger引擎層最多⽀持128的讀寫併發(這個值經過測試是⾮常
合理的經驗值,⽆需修改)。
而前面提到的“globalLock.currentQueue.readers”字段值,我的理解,就是目前等待提交到引擎層的請求排隊數量,而當這個數量持續不爲0時,說明系統的併發太⾼了,一般可以用下面兩種方式解決:
1)通過優化單個請求的處理時間(⽐如建索引來減少COLLSCAN或SORT)
2)升級後端資源(內存、磁盤IO能⼒、CPU)
gl_cq_readers/writers帶來的影響
案例中,主庫在11:32:42監控到gl_cq_writers爲18
從庫從11:43開始,gl_cq_readers持續在25~37
而具體是writers或redaers無關緊要,主要是出現了currentQueue的堆積,那麼這些處於等待隊列的數據庫請求耗時一定是比較長的,而這也是大部分“受牽連”的業務接口持續惡化的原因之一,反應出來的問題是併發太高,MongoDB服務質量下降。
遺留問題
本例中,在出現問題的一段時間內,從庫的CPU利用率持續在99%(不少接口在這個時間點出現超時),是否考慮下提升該數據庫的硬件配置,以提升服務處理能力?
總結
通過這次問題的分析,反推一下這次的關鍵線索:
1)服務接口整體變慢,包括那些平時良好的接口
2)gl_cq_readers/writers指標變化,持續不爲0
3)MongoDB CPU持續飆高
而後續接收到服務響應變慢的告警時,基本可以先用下面幾個步驟找到/排除典型慢查詢的問題:
1)找到服務出現問題的時間點
2)找到該時間點的主要問題接口,分析接口超時原因
3)如果因爲數據庫查詢耗時嚴重,到mongo監控中看下CPU利用率
4)觀察gl_cq_readers/writers指標
5)修復慢查詢,發佈驗證