一 問題現(xiàn)象
1辖源、現(xiàn)象一(2022年10月14號(hào)中午12點(diǎn)23分左右)
2022年10月14號(hào)中午12點(diǎn)23分左右谈喳,生產(chǎn)環(huán)境mc服務(wù)突然下線绿语,相關(guān)功能全部不可用倘屹,監(jiān)控組件也提示服務(wù)下線茬末。
三分鐘后厂榛,運(yùn)維先緊急重啟了,沒有來得及記錄當(dāng)時(shí)的dump文件丽惭。
雖然沒有dump文件击奶,但是我們還是可以從幾個(gè)方面去排查的:
(1)、機(jī)器環(huán)境(磁盤空間吐根、運(yùn)行內(nèi)存等)
磁盤空間充足正歼,通過長時(shí)間觀察運(yùn)行內(nèi)存情況、cpu占用情況拷橘,也沒發(fā)現(xiàn)任何異常局义。
(2)、服務(wù)被人為下線或kill
運(yùn)維通過排查機(jī)器運(yùn)行指令及通過nacos日志也排除了被人為下線和kill的因素冗疮。
(3)萄唇、JVM內(nèi)存溢出
通過分析mc當(dāng)時(shí)掛掉的前后日志,沒有發(fā)現(xiàn)任何異常术幔,-XX:HeapDumpPath=/home/smartcommunity/jvm/dump 目錄下也沒有任何的dump文件生成另萤,排除了JVM內(nèi)存溢出的可能。
(4)、tomcat線程數(shù)占滿了四敞,導(dǎo)致后續(xù)服務(wù)請(qǐng)求超時(shí)泛源,nacos心跳檢測(cè)服務(wù)下線
因?yàn)闆]有當(dāng)時(shí)的dump文件,我們只能通過日志去驗(yàn)證這個(gè)猜測(cè)忿危,通過查看gateway組件日志达箍,驗(yàn)證確實(shí)存在先請(qǐng)求超時(shí),后找不到服務(wù)的異常日志铺厨,具體查看以下文件缎玫。但是這也沒法直接驗(yàn)證是因?yàn)閠omcat線程數(shù)滿的問題引起的。
因?yàn)闆]有排查依據(jù)解滓,這個(gè)事情也就先耽擱了赃磨,直到。洼裤。邻辉。。逸邦。2022年10月25號(hào)
2恩沛、現(xiàn)象二(2022年10月25號(hào)早上8點(diǎn)40分左右)
2022年10月25號(hào)早上8點(diǎn)40分左右,生產(chǎn)mc組件再一次突然下線(監(jiān)控組件問題缕减,導(dǎo)致這次下線沒有發(fā)釘釘郵件提醒),可惜的是這次還是沒有及時(shí)記錄下dump文件芒珠。
老樣子桥狡,經(jīng)過排查排除了JVM內(nèi)存溢出、機(jī)器環(huán)境皱卓、服務(wù)被人為下線等因素裹芝。但是我們通過mc組件日志,發(fā)現(xiàn)了錯(cuò)誤日志娜汁。
因此嫂易,我們初步斷定是郵件健康檢查失敗引起的服務(wù)下線問題,但是缺少實(shí)質(zhì)性證據(jù)掐禁,我們只能反證這個(gè)結(jié)論怜械,當(dāng)時(shí)的驗(yàn)證思路可以查看這篇博客:一次線上問題處理——服務(wù)大量網(wǎng)絡(luò)連接處在close_wait狀態(tài)
后續(xù)經(jīng)過一系列猜測(cè)、模擬傅事、實(shí)驗(yàn)等缕允,始終沒法證實(shí)我們這個(gè)結(jié)論。
無奈之下蹭越,我們只能先將mc的郵件服務(wù)關(guān)停障本,如果后續(xù)沒有發(fā)現(xiàn)服務(wù)掛掉,那說明確實(shí)是郵件健康檢查失敗引起的服務(wù)下線。
3驾霜、現(xiàn)象三(2022年11月8號(hào)早上9點(diǎn)左右)
2022年11月8號(hào)早上9點(diǎn)左右案训,兩臺(tái)服務(wù)器上的mc實(shí)例全部下線。因?yàn)槲覀円呀?jīng)關(guān)停了郵件服務(wù)粪糙,這也否定了我們之前的結(jié)論(現(xiàn)象二猜測(cè))萤衰。
好在我們這次我們事先搭建了雙節(jié)點(diǎn),并且記錄下了當(dāng)時(shí)實(shí)例1的線程猜旬、內(nèi)存運(yùn)行情況脆栋,保留實(shí)例2作為排查目標(biāo)。這次洒擦,我們從頭分析一遍椿争。。熟嫩。
二 確認(rèn)原因
目前實(shí)例2是崩潰現(xiàn)場(chǎng)秦踪,我們直接從實(shí)例2服務(wù)器入手。掸茅。
1椅邓、問題定位一:垃圾回收線程占用大量cpu資源
因?yàn)橛星皟蓤?chǎng)事故的經(jīng)驗(yàn),很快就排除了JVM內(nèi)存溢出昧狮、服務(wù)被人為下線等因素景馁,但是這時(shí)候看實(shí)例2服務(wù)器上的cpu占用情況,我們發(fā)現(xiàn)了異常逗鸣,如下圖為cpu占用情況合住。
那么,我們看下是哪幾個(gè)線程占用了這么大的資源
接下來我們看下這幾個(gè)線程在做什么事情
很顯然撒璧,這幾個(gè)主要都是垃圾回收線程透葛。說明此刻JVM無法正常進(jìn)行回收,導(dǎo)致gc線程不斷在嘗試回收卿樱,占用了大量cpu資源僚害。
列名稱 | 描述 |
---|---|
S0 | S0(Survivor 0)空間使用百分比(相對(duì)于當(dāng)前容量) |
S1 | S1(Survivor 1)空間使用百分比(相對(duì)于當(dāng)前容量) |
E | Eden空間使用百分比(相對(duì)于當(dāng)前容量) |
O | 老年代空間使用百分比(相對(duì)于當(dāng)前容量) |
M | 元空間(Metaspace)使用百分比(相對(duì)于當(dāng)前容量) |
CCS | CCS空間使用百分比 |
YGC | 新生代GC(Minor GC/Young GC)發(fā)生的次數(shù) |
YGCT | YGC所消耗的時(shí)間, 單位s |
FGC | Full GC發(fā)生的次數(shù) |
FGCT | Full GC消耗的時(shí)間, 單位s |
GCT | 所有GC消耗的總時(shí)間, 單位s |
2、問題定位二:為什么垃圾回收會(huì)頻繁執(zhí)行繁调?什么資源占用了JVM內(nèi)存?
使用jmap指令dump內(nèi)存文件萨蚕,使用分析工具打開后,我們可以發(fā)現(xiàn)一個(gè)用戶tomcat線程占用了大量的內(nèi)存資源涉馁。
這時(shí)候我們看下這個(gè)線程對(duì)應(yīng)的堆棧信息
通過堆棧门岔,可以確定當(dāng)前占用大量內(nèi)存資源的線程執(zhí)行的業(yè)務(wù)邏輯,那么我們可以嘗試復(fù)現(xiàn)這個(gè)場(chǎng)景烤送。(這邊使用的是開發(fā)環(huán)境模擬)
然后gg了寒随,mc組件掛了... 查看nginx日志,發(fā)現(xiàn)響應(yīng)狀態(tài)碼499
10.100.25.229 - - [21/Nov/2022:19:34:09 +0800] "POST /web/mc/user/list/by-neigh HTTP/1.1" 499 0 "https://saasdev-54.leelen.net/sc/7183f3cb6f0134deb9940c1123ddb6fe/system/allConfig/process" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" "-" "30.018" "30.018"
這邊有個(gè)小插曲,按理來說當(dāng)前這個(gè)請(qǐng)求已經(jīng)進(jìn)入mc服務(wù)了妻往,那為什么我們沒有發(fā)現(xiàn)任何請(qǐng)求或者報(bào)錯(cuò)日志呢互艾?再怎么樣應(yīng)該也會(huì)有請(qǐng)求體的日志的?
原來讯泣,之前在針對(duì)佛山日志多問題進(jìn)行改造時(shí)纫普,對(duì)于日志量大、無關(guān)緊要的日志進(jìn)行了過濾好渠,這樣也影響了我們前兩次問題的排查昨稼。
三 尋找根源
根據(jù)線程堆棧信息,我們可以很快定位到具體的業(yè)務(wù)代碼拳锚。如下圖為問題接口:/rest/mc/web/user/list/by-neigh的業(yè)務(wù)方法
查看該線程的內(nèi)存占用情況假栓,可以看到QueryWrapper、DynamicContext霍掺、StringBuilder對(duì)象占了大部分內(nèi)存匾荆,那想必是Mybatis plus在處理in查詢時(shí)創(chuàng)建出來的對(duì)象。
使用jstack命令分析杆烁,發(fā)現(xiàn)該線程一直沒有釋放牙丽,處在運(yùn)行或等待狀態(tài)。
原因:
處理外部請(qǐng)求的工作線程兔魂,由于業(yè)務(wù)代碼上的bug烤芦,in查詢時(shí)傳入6萬多個(gè)小區(qū)號(hào),導(dǎo)致MybatisPlus創(chuàng)建了大量對(duì)象耗盡堆內(nèi)存(堆內(nèi)存原來分配太小256M入热,正撑淖兀空閑就幾十M),業(yè)務(wù)邏輯要繼續(xù)往下走發(fā)現(xiàn)內(nèi)存不足開始gc勺良。
jvm gc線程一直在嘗試回收垃圾對(duì)象,但是因?yàn)榫€程還沒有結(jié)束骄噪,占據(jù)大量堆內(nèi)存的對(duì)象均為GC Roots(工作線程)可達(dá)狀態(tài)尚困,無法被回收。
于是導(dǎo)致兩個(gè)問題:1链蕊、這幾個(gè)gc線程不斷進(jìn)行垃圾回收占用了大量cpu資源事甜; 2、jvm沒有可用堆內(nèi)存空間給新的請(qǐng)求去使用滔韵。
四 解決方案
1逻谦、該接口不需要小區(qū)相關(guān)信息,重寫一個(gè)構(gòu)造返回體方法
2陪蜻、擴(kuò)大堆內(nèi)存
由:-Xms256m -Xmx256m
修改為:-Xms2048m -Xmx2048m