最近線上監控 SFTP 連接頻繁爆表,通過重啟某個系統,連接數迅速下降,系統就能恢復正常,初步判斷是應用程式連接未關閉的問題導致的,
堆疊長通過 IDE 全域搜索排查,SFTP 連接使用了 jsch 包,確實有一些功能點使用了 SFTP 連接而未關閉的情況,或者不在 finally 陳述句塊中正常關閉,
整改上線后,SFTP 還是爆表……
事后運維心態都要崩了,運維主動寫了個 SFTP 連接監控,當連接超過 5 分鐘空閑時就主動斷開,
但這只是臨時的處理,真正的原因肯定還是應用程式沒有正常關閉導致的,于是再認真排查下程式,終于找出了元兇,,
下面是示例代碼:
Session session = null;
ChannelSftp channel = null;
try{
for(...){
...
// 創建會話
JSch jsch = new JSch();
jsch.getSession(host, username);
session = jsch.getSession(username, host, port);
session.setPassword(password);
session.connect();
// 創建sftp連接
channel = session.openChannel("sftp");
channel.connect();
...
}
} catch(...){
...
} finally{
if (null != channel && channel.isConnected()) {
channel.disconnect();
}
if (null != session && session.isConnected()) {
session.disconnect();
}
}
大家都看出問題了嗎?
這程式我檢查了 2 遍,排查了 3 天才解決了這個問題,
寫出這代碼,同事真是個人才啊!!!
乍一看,連接確實是關閉了啊,也確實是在 finally 陳述句塊關閉,為什么還會有問題?
原因就是在該死的 for 回圈中創建連接的,雖然在 finally 中進行了關閉,但是連接變數在回圈中進行重建和替換,所以關閉的永遠只是最后一個連接,
而且,這還是個下載 Excel 明細的功能,資料很多的時候,一個操作就能導致連接瞬間爆表,
解決方案肯定是要把創建連接的部分拿到 for 回圈前面去,連接創建一次就好了,可以反復使用,
另外,知道 JDK 7+ 中的 try-with-resources 語法的朋友可能會問,可以省略 finally 陳述句塊吧,可以直接在 try(...) 中定義,它會自動關閉,
Really?建議還是仔細閱讀下 try-with-resources 這篇文章吧,沒看過的可以關注公眾號Java技術堆疊進行搜索閱讀,
這個 jsch 連接包還真不行,我們來看它的原始碼吧,不然又是一個坑你沒商量的坑,
com.jcraft.jsch.Session:

com.jcraft.jsch.Channel:

這兩個類只實作了 Runnable 介面,沒有實作 java.lang.AutoCloseable 介面,所以,它并不符合 try-with-resources 自動關閉的原則,關于流關閉具體演進可以參考Java技術堆疊公眾號 "簡化流關閉新姿勢" 這篇文章,
至此,線上 SFTP 連接爆表的問題終于解決了,可以安心睡個好覺了,同時,我也感覺我們的同事太牛逼了,又讓我漲知識了,
大家引以為戒吧,也歡迎在看、轉發!
關注公眾號Java技術堆疊回復"面試"獲取我整理的2020最全面試題及答案,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/124088.html
標籤:Java
