tanger
发布于 2024-03-21 / 3 阅读 / 0 评论 / 0 点赞

Netty报错Too many open files解决方案

Netty报错Too many open files解决方案

使用netty做了一个TCP/IP的通讯服务,我们作为TCP的服务端接收客户端发送的请求,项目部署在Linux环境下运行。但是运行一段时间,服务就崩了,报错内容如上:java.io.IOException: 打开的文件过多 或 java.io.IOException: Too many open files。反正意思一样,都是当前服务文件句柄数超出上限,内存达到上限,服务承受不住了。这个时候把netty服务重启一下就又恢复了…循环往复,苦不堪言

一般出现这类问题,都是在网上一通搜索,基本的方案不外乎以下几种:

🚀方案一,升级netty的版本

结果:没用

版本升级之后,运行一段时间又成这样了,肯定不是版本的问题了

🚀方案二,初始化NioEventLoopGroup的时候,传参限制1个

EventLoopGroup bossGroup = new NioEventLoopGroup(1);

结果:没用

网上有些人真的是误人子弟,你抄我、我抄你的,本来实例化的也是1个对象,这样改有什么意义呢?

🚀方案三,修改/etc/security/limits.conf中的数量限制,默认是1024,改为65536

* soft nofile 65536
* hard nofile 65536

结果:短时间有用,运行几天之后又报这个错了

典型的治标不治本。这种情况针对的是并发很高,TCP客户端超过1024了,但是我们总共就100多个客户端,怎么会超出呢。改了这个只把句柄数量上限提高了,根本上还是没有解决问题,过几天还是要崩的!

💔行了,网上的解决方案都没用,只能靠自己分析报错原因了。客户端总共就100多个,怎么过几天就超过65536了呢?肯定是单个客户端建立了多次连接,但是服务端的连接没有及时关闭所致。正常客户端会主动断开连接并重新建立连接,而这个项目的客户端可能就没有做断开操作,而是不断向服务端建立新的连接,所以我们要在服务端做好处理了。

查询服务倒序连接数,可以看到linux下所以服务进程号对应的连接数量,从高到低排序

lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|more

查询某进程号连接数,此时我的netty服务对应的进程号是5655,间隔时间多查几次,发现连接数量在不断递增,早就超过了预留客户端的数量

netstat -lnaop|grep 5655|wc -l

查询某端口客户端连接的情况,此时我netty服务开放的TCP端口是10072,列表查到占用资源的客户端列表,发现大量重复的客户端IP地址

netstat -ntu | grep 10072

👍 重点来了,解决根本问题

最终解决方案:netty初始化的时候,设置连接超时时间

pipeline.addLast(new ReadTimeoutHandler(timeoutSeconds))

/**

 * 设置初始化器,主要是给pipeLine添加Handler

 */

public class MyServerInitializer  extends ChannelInitializer<SocketChannel> {

    @Override

    protected void initChannel(SocketChannel ch) throws Exception {

        ChannelPipeline pipeline = ch.pipeline();

        

        //设置2min的超时时间,如果某个通道2min内未发送信号,则抛出异常删除当前通道

        pipeline.addLast(new ReadTimeoutHandler(120));

        

        pipeline.addLast("encoder",new StringEncoder(CharsetUtil.UTF_8));

        pipeline.addLast("decoder",new StringDecoder(CharsetUtil.UTF_8));

        pipeline.addLast(new MyServerHandler());

    }

}

我这边设置的是2分钟,具体按照项目的实际需求设置,因为我这边的客户端是每1分钟发送一次报文的,我就暂时设置为2分钟了。超过2分钟没发数据,服务端就认为这个连接超时了,超时就会在执行到exceptionCaught方法中并且断开当前连接。我们的MyServerHandler类继承了ChannelInboundHandlerAdapter类或SimpleChannelInboundHandler类,自然而然就重写了exceptionCaught这个方法。而netty框架中某通道发生异常的时候,会在执行到exceptionCaught方法中。

这样我们就完美解决了这个问题,间隔时间多跑几次【netstat -lnaop|grep 5655|wc -l】命令,会发现连接数稳定在100多个了!


评论