MINA java.io.IOException: Too many open files

这个问题,本来应该在文档中进行提示和重点说明的内容,但是框架本身并没有提示,NIOsocketconection和session需要手动进行关闭的问题。这个问题并不是高并发才会产生的,只要持续一段就会发生这个问题,默认1024的文件描述符很快就会保罗问题。

参考  http://blog.csdn.net/w93223010/article/details/9027605

        https://www.cnblogs.com/jacklondon/archive/2011/03/16/1985926.html

一、问题描述

   产生 java.io.IOException: Too many open files 错误。

  通过 lsof -c java 观察程序描述符占用情况会出现成堆的

         java  pid     --    20r   FIFO    0,6       pipe 

                                   20w  FIFO   

这一类占用


1.打开的文件没有关闭

2.通讯连接没有完全关闭

二、他人解决办法

a. 使用到 NioSocketAcceptor 一个,用来 listen ,没有问题。

b. 自定义 IoHandlerAdapter 在 Mina 中是 Singleton, 只创建一次,也没有问题。

c. 自定义 IoHandlerAdapter 中需要有以下代码:

public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        session.close(true);//force close right now
}

public void sessionOpened(IoSession session) throws Exception {
    session.getConfig().setBothIdleTime(180);//set timeout seconds, must
}
public void sessionIdle(IoSession session, IdleStatus status) throws Exception {
    session.close(true);//timeout now, close it
}

f. 系统中使用了以下 Mina NIO 的 Java 对象:

    NioSocketAcceptor 用来 listen, 1个,配 1 个 IoHandlerAdapter

每次 1 客户 socket 连接,对应1 个 IoSession, 创建 1 个 NioSocketConnector 连接后端服务器,然后自动创建一个 IoSession 作为当前客户 socket 的 peer (同伴),也就是两个 IoSession 有对应关系。

g. 无论是客户 socket 连接的 IoSession 还是 peer IoSession , 在 sessionClosed 中需要调用 peer.close(false); 这里的 close(false) 不是立即关闭,而是让 peer 发完数据再关闭。这是由 NIO 这种异步操作特性决定的。这里不会造成死循环: client IoSession 调用 peer.close(false), 而 peer 反过来调用 client IoSession.close(false)。好像 Mina 做了特别处理。

h. 特别的提醒,NioSocketConnector 也要关闭。函数名是 dispose()。这点特别重要。这次出现 too many open files 的问题根源在这里。而 Mina 文档中只字不提。而 NioSocketConnector 与 peer IoSession 使用 127.0.0.1 端随机端口连接,匪夷所思。

而 peer IoSession 关闭后,没有关闭 NioSocketConnector , 也没有给它发 close event, 或者让它进入 exception, 这种设计也不好。 IoSession 关闭后,留着 NioSocketConnector 也是无用,还白白成了一个 ESTABLISHED 状态的连接,导致 socket leak。 这似乎就是所谓的半开 socket ? 还是觉得 Mina 这种设计不好。

三、我的解决方式

   针对第c  和第h条

  讲NioSocketConnector  实例存储到session

NioSocketConnector conn =null;
        IoSession session = null;
        ConnectFuture connectFuture = null;
        try{
            conn   = new NioSocketConnector();
            DefaultIoFilterChainBuilder chain = conn.getFilterChain();
            chain.addLast("logger", new LoggingFilter());
            chain.addLast("mdc",    new MdcInjectionFilter());
            chain.addLast("codec",  new ProtocolCodecFilter(protocolCodecFactory));
            conn.setHandler(ioHandler);
            //重复三次

            conn.setConnectTimeoutMillis(DefaultConnectTimeOut);


            connectFuture = conn.connect(addr);
            connectFuture.awaitUninterruptibly();

            if  (connectFuture.isDone()) {
                if  (!connectFuture.isConnected()) {  //若在指定时间内没连接成功,则抛出异常
                    LOGGER.info("fail to connect "  );
                    conn.dispose();    //不关闭的话会运行一段时间后抛出,too many open files异常,导致无法连接
                    throw   new  Exception();
                }
            }
            session = connectFuture.getSession();
            session.setAttribute(CONNECTER,conn);

            LOGGER.debug("链接成功{},{}",session.getId(),session.getRemoteAddress());
然后在后续的
exceptionCaught
sessionOpened

sessionIdle

中取出connection  判断装填然后dispose

 NioSocketConnector conn =(NioSocketConnector) session.getAttribute(SocketUtils.CONNECTER);
        if( conn != null && conn.isActive()){
            conn.dispose();
            LOGGER.debug("connection is closed");
        }
        session.closeNow();

四、目前文件描述符数目可控,看看运行结果

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值