1. 程式人生 > 實用技巧 >同事牛逼啊,寫了個隱藏 bug,我排查了 3 天才解決問題!

同事牛逼啊,寫了個隱藏 bug,我排查了 3 天才解決問題!

最近線上監控 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、後端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!