• 记录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地址

  • 相关阅读:
    小程序的媒体组件
    微信小程序开发系列之Hello World
    centos 6 mysql 5.6 源码安装
    php 源码安装
    centos7 源码安装nginx
    CentOS 7.2部署MariaDB Galera Cluster(10.1.21-MariaDB) 3主集群环境
    MySQL读写分离
    MySQL主从复制(Master-Slave)实践
    lvs+keepalived+nginx负载均衡搭建
    Kubernetes在CentOS7下二进制文件方式安装、离线安装
  • 原文地址:https://www.cnblogs.com/qq931399960/p/11679682.html
Copyright © 2020-2023  润新知