記錄Redis連接未正確釋放,TCP連接過多,造成服務器上部分功能不可用和linux服務器內存一直增加問題


問題1

多人共享開發服務器(windows系統),我們小組有個程序,定時檢測mongodb,redis,mysql連接是否正常,程序啟動一段時間后,服務器管理人員找到我們說,我們的某個pid的程序把TCP連接占滿了,很多功能都不可使用,第一次調查發現未關閉連接,然后修改了,修改之后還是會出現TCP連接被全部耗盡的情況。

調查

復現問題

啟動上述問題程序,找到其對應的java的pid,查看其建立的線程數

netstat -ano | findstr "28720" | find /v /c ""

發現TCP連接在很短的時間內,增長非常快,程序的確有問題

 由於我們程序中比較占用TCP的就只有在獲取上述三個服務連接的時候,同事講關閉連接沒問題,所以也就沒有怎么注意那塊,有同事反饋mongodb,mysql,redis都正常連接的時候沒有出現問題,故分別停掉以上三個數據庫,查看該程序占用的TCP連接數

最后發現,停掉redis的時候,TCP連接數增長非常快,所以懷疑是redis連接問題,最后還是要去看下代碼,經過查看代碼,找到了一個懷疑的點,代碼中是這么寫的

private RedisClient client;
private StatefulRedisConnection<String,String> conn;

public void redisTest(){
    try{
        client=...
        conn=...
        ....
    }catch(Exception e){
        logger.error("",e)
    }finally{
        try{
            conn.close();
            client.close();
        }catch(Exception ex){
            logger.error("",ex)
        }
    }
}

乍一看,似乎沒什么大問題,但這里隱藏了一個不是必現的BUG,由於我們一般啟動程序時,都會配置正確連接,但如果上面的conn為空怎么辦嘞,很明顯會發生空指針,后面的client連接自然就不會釋放,但奇怪的是,在日志文件中也並沒有發現空指針異常日志輸出。

為了驗證猜想,在finally中分別打印出上述conn和client的值

 驗證了猜想,conn為空,造成后面的client未被釋放。找到了問題,代碼修改比較簡單,只需要在finally塊中對conn和client做非空判斷即可

}finally{
        try{
            if (conn != null){
                conn.close();
            } 
            if(client != null){
                client.close();
            }
        }catch(Exception ex){
            logger.error("",ex)
        }
    }

連接不釋放,TCP連接一直快速增長,造成的危害很大,在代碼中,關閉多個連接時,一定要注意非空判斷。

問題2

 程序跑一段時間,內存占用超過了平時的4,5倍

調查

網上有講在使用free -m查看內存時,不能只看used,因為在linux的內存分配機制中,優先使用物理內存,當物理內存還有空閑時,不會釋放其占用內存,就算占用內存的程序已經被關閉了,該程序所占用的內存用來做緩存使用,對於開啟過的程序、或是讀取剛存取過得數據會比較快,應該查看buffers/cached+free,才是可用內存,但通過free -m查看本機的內存占用時,發現buffers/cached+free占用的內存不多,實際被使用到的內存達到了30個G,通過top命令查看每個程序占用到的內存也並不多,每個程序占用內存的百分比都很少,VIRT占用比較大,但它並不是程序占用的內存。

我們知道每個TCP連接也是耗內存的,那會不會是連接數過多造成的內存劇增,查看連接數

netstat -na | grep ESTABLISHED

發現有某個地址的連接非常多

 查看當前機器總共建立連接

[root@localhost data]# netstat -na|grep ESTABLISHED|wc -l
21127

該鏈接數還在增長,查看上述出現次數比較多的tcp連接數量(肉眼查看到的,比較low的方法,其實可以用腳本統計處每個外部地址占用的連接數)

[root@localhost data]# netstat -na|grep ESTABLISHED|grep ip_addr |wc -l
21121

發現幾乎所有建立的連接都來自這台外部機器,這台機器部署的了一個模擬程序,停止模擬程序,內存恢復到正常狀態。

 

腳本統計每個連接到本機的ip的TCP連接數

netstat -na | grep ESTABLISHED | awk '{print $5}'| awk -F ":" '{print $1}'| sort | uniq -c

 第一行為連接總數,第二行為連接當前服務器ip地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM