CPU過高問題排查

目錄

  • 背景
  • 實(shí)戰(zhàn)
    • 問題定位之純命令式
    • 問題定位之阿里的Arthas工具查詢Cpu占用高
    • 問題處理
    • 問題原因分析
  • 參考文章

背景

  • 線上的業(yè)務(wù)是一個(gè)后臺(tái)管理系統(tǒng),并發(fā)量和QPS都不高,今天線上遇到CPU突然飆到100%,查看Grafana發(fā)現(xiàn)QPS,堆內(nèi)外內(nèi)存,Pod內(nèi)存均正常。由于是后臺(tái)管理系統(tǒng),跟運(yùn)營同步之后,有問題的Pod先用于分析,后臺(tái)功能先不使用。所以也沒有把Pod拉出去,也沒有執(zhí)行回滾操作(前天有發(fā)布新版本)

實(shí)戰(zhàn)

  • 進(jìn)入阿里云對應(yīng)的Pod,終端執(zhí)行命令,分析問題,有兩種方式

問題定位之純命令式

  • 這邊只是舉個(gè)例子,用命令式排查cpu高的思路
  1. top查看占用對應(yīng)Pid, 然后top -Hp查看pid下對應(yīng)線程占用如下圖


    Pid下線程id.png
  2. 3860轉(zhuǎn)16進(jìn)制,結(jié)果是f14,然后jps看下java進(jìn)程是2134, jsatck 2134 | grep f14看看結(jié)果, jps的時(shí)候記得要跟部署應(yīng)用同一個(gè)賬號,比如你是root部署應(yīng)該,那也要root登錄


    命令形式排查.png
  3. 上圖查看到是一個(gè)定時(shí)任務(wù)的線程占用高,具體問題到項(xiàng)目代碼,發(fā)現(xiàn)sql返回的數(shù)據(jù)量太大,cpu占用比較大,這邊優(yōu)化sql解決
  4. 再舉個(gè)例子,jstack pid |grep 3f,具體問題代碼沒截出來,但是能知道哪一行代碼問題


    正則

問題定位之阿里的Arthas工具查詢Cpu占用高

  • 在終端執(zhí)行下載
wget https://alibaba.github.io/arthas/arthas-boot.jar
  • 運(yùn)行
java -jar arthas-boot.jar
Arthas.png
  • 查看運(yùn)行情況, 紅框部分就是罪魁禍?zhǔn)?/li>
dashboard
Arthas_1.png
  • 查看占用最高cpu線程詳情信息, 堆棧信息沒截全,最后會(huì)輸出具體哪行代碼
thread pid(51)
Arthas_2.png

問題處理

  • 由Arthas定位到問題代碼是, 正則匹配引起的,產(chǎn)品功能是配置鏈接,后端這邊簡單校驗(yàn)鏈接,有問題代碼是這個(gè), 觸發(fā)的原因是產(chǎn)品在配置鏈接時(shí)類似給了https://www.baidu.com/6sfs3sfsa-ggsfdsf-4wrwrwr-geerw-9d094636cab9?#, 地址結(jié)構(gòu)是這樣的,真實(shí)地址隱藏了
Pattern pattern = Pattern.compile("^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\\\/])+$")
if (!pattern.matcher(sr.getLink()).matches()) {
 ...
}
  • 與產(chǎn)品溝通鏈接可簡單校驗(yàn),后來改成, 重新發(fā)布,問題解決,產(chǎn)品之前那個(gè)有問題的鏈接能夠正常配置
Pattern pattern = Pattern.compile("^(|http|https):[^ \"]+$")
if (!pattern.matcher(sr.getLink()).matches()) {
 ...
}

問題原因分析

  • Java 正則表達(dá)式使用的引擎實(shí)現(xiàn)是 NFA 自動(dòng)機(jī),這種正則表達(dá)式引擎在進(jìn)行字符匹配時(shí)會(huì)發(fā)生回溯。而一旦發(fā)生回溯,那其消耗的時(shí)間就會(huì)變得很長,有可能是幾分鐘,也有可能是幾個(gè)小時(shí),時(shí)間長短取決于回溯的次數(shù)和復(fù)雜度
  • NFA自動(dòng)機(jī)匹配原則, 如下例子正則匹配是拿regex的d跟text文本一個(gè)個(gè)匹配,d先個(gè)T匹配不匹配,d再跟o匹配不匹配,d跟d匹配則匹配,再拿regex的a跟text中d后面的a匹配能匹配,y跟y匹配能匹配,當(dāng)然實(shí)際匹配比這個(gè)復(fù)雜很多
text = Today is a nice day
regex = day
  • NFA自動(dòng)回溯,例子是regex以a開頭,以c結(jié)尾,中間有1-3個(gè)b字符的字符串。NFA解析: 讀取正則表達(dá)式第一個(gè)匹配符a和 字符串第一個(gè)字符 a 比較,匹配了。于是讀取正則表達(dá)式第二個(gè)字符。讀取正則表達(dá)式第二個(gè)匹配符 b{1,3} 和字符串的第二個(gè)字符 b 比較,匹配了。但因?yàn)?b{1,3} 表示 1-3 個(gè) b 字符串,以及 NFA 自動(dòng)機(jī)的貪婪特性(也就是說要盡可能多地匹配),所以此時(shí)并不會(huì)再去讀取下一個(gè)正則表達(dá)式的匹配符,而是依舊使用 b{1,3} 和字符串的第三個(gè)字符 b 比較,發(fā)現(xiàn)還是匹配。于是繼續(xù)使用 b{1,3} 和字符串的第四個(gè)字符 c 比較,發(fā)現(xiàn)不匹配了。此時(shí)就會(huì)發(fā)生回溯。發(fā)生回溯是怎么操作呢?發(fā)生回溯后,我們已經(jīng)讀取的字符串第四個(gè)字符 c 將被吐出去,指針回到第三個(gè)字符串的位置。之后,程序讀取正則表達(dá)式的下一個(gè)操作符 c,讀取當(dāng)前指針的下一個(gè)字符 c 進(jìn)行對比,發(fā)現(xiàn)匹配則結(jié)束
text = abbc
regex = ab{1,3}c
  • 我們有問題的正則
^([hH][tT]{2}[pP]://|[hH][tT]{2}[pP][sS]://)(([A-Za-z0-9-~]+).)+([A-Za-z0-9-~\\\\/])+$
  • 第二部分, 匹配到com/6sfs3sfsa-ggsfdsf-4wrwrwr-geerw-9d094636cab9?#, 你因?yàn)樨澙菲ヅ涞脑?,所以程序?huì)一直讀后面的字符串進(jìn)行匹配,最后發(fā)現(xiàn)沒有點(diǎn)號,于是就一個(gè)個(gè)字符回溯回去了,這是第一個(gè)問題
(([A-Za-z0-9-~]+).)+
  • 第三部分, 需要匹配的鏈接是有特殊符號?#的,但是對應(yīng)第三部分的正則表達(dá)式里面卻沒有。這樣就會(huì)導(dǎo)致前面匹配了一長串的字符之后,發(fā)現(xiàn)不匹配,最后回溯回去,時(shí)間就比較長了
([A-Za-z0-9-~\\/])+$

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容