線上Spring CPU 高負(fù)載解決思路詳解
引言
背景: 在某一天,運(yùn)營(yíng)同事突然發(fā)現(xiàn)運(yùn)營(yíng)看板好幾天沒有更新數(shù)據(jù)了, 然后找了過來?!
這里看似拋出了一個(gè)問題 ?
但細(xì)想一下, 同時(shí)暴露了我們對(duì)于線上服務(wù)的監(jiān)控未完全覆蓋到!!! 這是致命的!!!
當(dāng)然, 這篇文章先不討論監(jiān)控的問題, 后面會(huì)推出完善的監(jiān)控方案
定位問題
問題拋過來了, 那么我們第一步要怎樣做呢?
拿到問題的第一步, 先理解題意, 這里有幾個(gè)關(guān)鍵的信息點(diǎn)
第一 : 好幾天, 具體哪一天, 這個(gè)后面確認(rèn)了一個(gè)具體的時(shí)間點(diǎn)
第二 : 運(yùn)營(yíng)看板, 這是重點(diǎn), 是我們切入問題的關(guān)鍵
好了, 有了這兩個(gè)關(guān)鍵的信息, 我們接下來就開始定位問題代碼了
- 從功能出發(fā), 定位到未更新的表
- 通過表來定位到更新數(shù)據(jù)的代碼
通過上面兩步找到了問題代碼是某個(gè)定時(shí)任務(wù)
日志搜索
這時(shí)按照肌肉記憶, 先是看了代碼有沒有關(guān)鍵點(diǎn)的日志輸出, 發(fā)現(xiàn)代碼開始和結(jié)束都有打印日志的操作
順藤摸瓜,先登錄到服務(wù)器端, grep一波關(guān)鍵的日志
發(fā)現(xiàn)當(dāng)天的 info.log 沒有打印到日志, 這就很奇怪了, 因?yàn)檫@個(gè)定時(shí)任務(wù)的 cron 是每天凌晨1點(diǎn)開始
然后就查了前一天的日志, 發(fā)現(xiàn)有打印到開始的日志, 但是沒有打印結(jié)束的日志
然后再去找看有沒有異常的日志, 發(fā)現(xiàn)并沒有
監(jiān)控看板
從日志看出了一點(diǎn)不對(duì)勁的味道, 但還沒有足夠的線索定位到具體的問題
這時(shí)去查看容器的資源情況
這里觀察的是, 在兩臺(tái)容器中, 有一臺(tái)容器的 cpu 吃得很緊
另外一臺(tái)卻是風(fēng)平浪靜
從這里可以定位到大概的問題了: CPU負(fù)載高
那為什么會(huì)造成 CPU 跑那么高呢 ?
ThreadDump
當(dāng)然有很多方案可以定位 CPU 的瓶頸問題,像使用火焰圖定位(下一篇會(huì)使用到)
但從上面的蛛絲馬跡里可以大體定位到是具體的定時(shí)任務(wù)引起的
這時(shí) threaddump, 并分析了一波線程的運(yùn)行情況
從整體的報(bào)告可以看出有阻塞的線程兩個(gè), 同時(shí)有百分之四十是在超時(shí)等待
再看看具體被阻塞的線程
看起來是數(shù)據(jù)庫查詢阻塞
看具體的業(yè)務(wù)代碼
分析一下這條 SQL 的變量
入?yún)⒅挥幸粋€(gè)就是 classIds 數(shù)組:
- 數(shù)量很小
- 數(shù)量很大
- 數(shù)量為 0
數(shù)組的分布情況可以為上面幾種
套進(jìn)去
- 數(shù)量很小, 查詢應(yīng)該很快
- 數(shù)量很大, 查詢應(yīng)該會(huì)相對(duì)慢一點(diǎn)
- 數(shù)量為 0 呢, if 標(biāo)簽, classIds 數(shù)量為 0, 不會(huì) 拼接下面的 sql, 也就是會(huì)查全表
優(yōu)化
定位到具體的代碼了, 那就是要出優(yōu)化方案了
做法就是當(dāng) classIds 的大小為 0 的時(shí)候, 不要掃描全表
這里添加 otherwise 分支, classIds 大小為 0 是 and false
重新部署再觀察線上情況, CPU 降了下來
事后反思
為什么會(huì)這么久才發(fā)現(xiàn)問題? 而且依賴于業(yè)務(wù)側(cè)發(fā)現(xiàn)問題
能不能提前感知問題呢?
想了一下, 我們的監(jiān)控更多是在監(jiān)測(cè)代碼拋出異常, 對(duì)于操作系統(tǒng)的資源缺少監(jiān)控 下一步的優(yōu)化, 對(duì)操作系統(tǒng)資源進(jìn)行監(jiān)控
以上就是線上Spring CPU 高負(fù)載解決思路詳解的詳細(xì)內(nèi)容,更多關(guān)于線上Spring CPU 高負(fù)載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaWeb開發(fā)之JSTL標(biāo)簽庫的使用、 自定義EL函數(shù)、自定義標(biāo)簽(帶屬性的、帶標(biāo)簽體的)
這篇文章主要介紹了JavaWeb開發(fā)之JSTL標(biāo)簽庫的使用、 自定義EL函數(shù)、自定義標(biāo)簽(帶屬性的、帶標(biāo)簽體的),需要的朋友可以參考下2017-02-02JProfiler11使用教程之JVM調(diào)優(yōu)問題小結(jié)
這篇文章主要介紹了JProfiler11使用教程之JVM調(diào)優(yōu),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03SpringCloud Eureka服務(wù)發(fā)現(xiàn)實(shí)現(xiàn)過程
這篇文章主要介紹了SpringCloud Eureka服務(wù)發(fā)現(xiàn)實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11Springboot配置Swagger2登錄密碼的實(shí)現(xiàn)
本文主要介紹了Springboot配置Swagger2登錄密碼的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03解決java.util.NoSuchElementException異常正確方法
java.util.NoSuchElementException是Java中的一種異常,表示在迭代器或枚舉中找不到元素,這篇文章主要給大家介紹了關(guān)于解決java.util.NoSuchElementException異常的相關(guān)資料,需要的朋友可以參考下2023-11-11