記一次線程爆滿導致服務器崩潰的問題排查及解決
問題介紹
測試服務器突然無法連接,ssh登錄不上。只有重啟才能解決。重啟一天后,又連接不上了。
于是有了下面的排查過程,最終發(fā)現(xiàn)是有個java程序一直在創(chuàng)建線程,導致線程達到服務器最大數(shù)量,服務器崩潰。
1. 重啟服務器
重啟后,ssh連接發(fā)現(xiàn)下面問題
fork faild:Cannot allocate memory
以為是內存滿了
于是,free -h,查看內存情況,還有,觀察一段時間后,內存沒多大變化
2. 修改最大線程數(shù)
經過各種百度,都說可以通過修改服務器的最大線程數(shù)來解決,于是我也這么干了。當時做的時候沒有截圖,所以下面截圖是網(wǎng)上找的,湊合看看。
查看最大進程數(shù) sysctl kernel.pid_max
ps -eLf | wc -l查看 進 程數(shù)
修改最大 進 程數(shù)后系統(tǒng)恢復
echo 1000000 > /proc/sys/kernel/pid_max
永久生效
echo "kernel.pid_max=1000000 " >> /etc/sysctl.conf sysctl -p
3. 查找線程最大的java程序
上一步擴大了線程數(shù)量后,感覺有點不對,因為之前沒有這么配置都可以正常運行,為什么突然服務器掛了呢?肯定是有程序在作怪。
于是決定找出占用線程最多的程序。回顧最近幾天,服務器中只部署了幾個springboot程序。問題一定出在它們之中。
查看線程數(shù)量前20的java程序
ps -Lef |awk ‘{sum[$2]++}END{for(pid in sum) print pid, sum[pid]}'|sort -nr -k 2|head -n 20
[root@se-test-lky01 ~]# ps -Lef |awk '{sum[$2]++}END{for(pid in sum) print pid, sum[pid]}'|sort -nr -k 2|head -n 20 16074 3100 31386 1226 20120 1072 19548 985 9697 829 3005 796 641 344 19016 324 16924 315 17870 300 6417 293 8351 171 7332 168 18259 167 19821 161 16311 157 18433 151 18048 136 14347 104 2559 100
觀察一段時間后,發(fā)現(xiàn)進程id為16074的java程序的線程數(shù)不斷增長。
4. 導出問題程序的線程日志
[root@se-test-lky01 ~]#jstack 16074 >thread_dump.log
分析日志,發(fā)現(xiàn)下面情況,線程數(shù)量不斷增加,代碼位置在FtpMonitorProcess.java:85
"Thread-4655" #4774 prio=5 os_prio=0 tid=0x00007f84aa2fe000 nid=0xd408b waiting for monitor entry [0x00007f802b704000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.cloudwalk.bat.util.http.FtpUtil.connect(FtpUtil.java:246) - waiting to lock <0x00000006c09c1888> (a java.lang.Class for cn.cloudwalk.bat.util.http.FtpUtil) at cn.cloudwalk.bat.schedule.ftp.process.FtpMonitorProcess$1.run(FtpMonitorProcess.java:85) at java.lang.Thread.run(Thread.java:748) "Thread-4654" #4773 prio=5 os_prio=0 tid=0x00007f84aa2fc000 nid=0xd408a waiting for monitor entry [0x00007f802b805000] java.lang.Thread.State: BLOCKED (on object monitor) at cn.cloudwalk.bat.util.http.FtpUtil.connect(FtpUtil.java:246) - waiting to lock <0x00000006c09c1888> (a java.lang.Class for cn.cloudwalk.bat.util.http.FtpUtil) at cn.cloudwalk.bat.schedule.ftp.process.FtpMonitorProcess$2.run(FtpMonitorProcess.java:114) at java.lang.Thread.run(Thread.java:748)
5. 找到問題代碼
發(fā)現(xiàn)這個方法每次被調用就會創(chuàng)建一個新的線程。而這個方法是被定時任務調用的,每10秒調用一次。
問題就出在ftp沒有配置,所以線程內執(zhí)行ftp操作時,線程阻塞,沒能釋放。若ftp可用,則不會出現(xiàn)線程阻塞問題。
這就是問題根源。
private void listDeviceFiles() { new Thread(new Runnable() { @Override public void run() { logger.debug("開始獲取[ftp-設備]文件..."); try { String workDir = ftpConfig.getWorkdir(); // 連接 FTPClient ftpClient = FtpUtil.connect(ftpConfig); ftpClient.changeWorkingDirectory(workDir); ftpClient.changeWorkingDirectory(SubscribeDataTypeEnum.DEVICE_INFO.getKey().toString()); FTPFile[] files = ftpClient.listFiles(); for(FTPFile file : files) { decomposeFile(file,ftpClient); } ftpClient.logout(); } catch (Exception e) { logger.error("ftp獲取文件名出錯:" + e.getMessage()); } } }).start(); }
6. 解決方案
不建議手動創(chuàng)建線程,改用使用線程池。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
SpringCloud?Eureka服務治理之服務注冊服務發(fā)現(xiàn)
這篇文章主要介紹了SpringCloud?Eureka服務治理服務注冊和服務發(fā)現(xiàn)概念詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08SpringBoot整合Hutool實現(xiàn)文件上傳的使用示例
文件上傳在項目經常會用到,本文主要介紹了SpringBoot整合Hutool實現(xiàn)文件上傳的使用示例,具有一定的參考價值,感興趣的可以了解一下2023-11-11Spring boot自定義http反饋狀態(tài)碼詳解
這篇文章主要給大家介紹了Spring boot自定義http反饋狀態(tài)碼的相關資料,文中介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編一起來學習學習吧。2017-06-06