mina高并发短连接导致java.io.IOException: Too many open files解决方案

这几天在解决一个用mina开发的高并发通信过程中产生的一个bug。

   模拟场景为:

   通过定时触发启动线程模拟高并发短连接测试,测试的服务端有2个,一个是服务有起,一个没起,客户端和服务端均在同一服务器上。执行一段时间后linux主机上通过lsof命令查看,发现有递增的文件句柄,pipe和eventpoll。

   抛出的异常如下:

 

2012 - 10 - 13   10 : 09 : 48  -org.apache.mina.core.service.SimpleIoProcessorPool.(SimpleIoProcessorPool.java: 197 )    
2. Failed to create a new  instance of org.apache.mina.transport.socket.nio.NioProcessor: null     
3.java.lang.reflect.InvocationTargetException   
4.        at sun.reflect.GeneratedConstructorAccessor110.newInstance(Unknown Source)   
5.        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27 )    
6.        at java.lang.reflect.Constructor.newInstance(Constructor.java:513 )    
7.        at org.apache.mina.core.service.SimpleIoProcessorPool.(SimpleIoProcessorPool.java:180 )    
8.        at org.apache.mina.core.service.SimpleIoProcessorPool.(SimpleIoProcessorPool.java:112 )    
9.        at org.apache.mina.core.polling.AbstractPollingIoConnector.(AbstractPollingIoConnector.java:93 )    
10.        at org.apache.mina.transport.socket.nio.NioSocketConnector.(NioSocketConnector.java:56 )    
11.        at com.develop.webplatform.funnel.client.JobClient.sendMessage(JobClient.java:39 )    
12.        at com.develop.webplatform.funnel.client.JobClient.sendJob(JobClient.java:126 )    
13.        at com.develop.webplatform.funnel.extend.JobExecRemotelyBySocket.execJobByTask(JobExecRemotelyBySocket.java:66 )    
14.        at com.develop.webplatform.funnel.JobManager.execJobByTask(JobManager.java:27 )    
15.        at com.develop.webplatform.quartz.job.TaskJob.executeInternal(TaskJob.java:38 )    
16.        at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86 )    
17.        at org.quartz.core.JobRunShell.run(JobRunShell.java:223 )    
18.        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549 )    
19.Caused by: org.apache.mina.core.RuntimeIoException: Failed to open a selector.   
20.        at org.apache.mina.transport.socket.nio.NioProcessor.(NioProcessor.java:61 )    
21.        ... 15  more    
22.Caused by: java.io.IOException: Too many open files   
23.        at sun.nio.ch.IOUtil.initPipe(Native Method)   
24.        at sun.nio.ch.EPollSelectorImpl.(EPollSelectorImpl.java:49 )    
25.        at sun.nio.ch.EPollSelectorProvider.openSelector(EPollSelectorProvider.java:18 )    
26.        at java.nio.channels.Selector.open(Selector.java:209 )    
27.        at org.apache.mina.transport.socket.nio.NioProcessor.(NioProcessor.java:59 )    
28.        ... 15  more  


源代码中,关于客户端连接的代码如下:

final  NioSocketConnector connector =  new  NioSocketConnector();    
2.        final  String[] result =  new  String[ 1 ];    
3.        connector.getFilterChain().addLast("codec" ,    
4.                new  ProtocolCodecFilter( new  ObjectSerializationCodecFactory()));    
5.        connector.setHandler(handler);   
6.   
7.        //设置超时     
8.        connector.setConnectTimeoutMillis(defaultConnectTimeOut);   
9.        ConnectFuture connectFuture = connector.connect(address);   
10.        connectFuture.awaitUninterruptibly();   //同步,等待,直到连接完成     
11.        if  (connectFuture.isDone()) {    
12.            if  (!connectFuture.isConnected()) {  //若在指定时间内没连接成功,则抛出异常     
13.                logger.info("fail to connect "  + logInfo);    
14.   
15.                throw   new  Exception();    
16.            }   
17.        }


经过分析,导致主机文件句柄泄露的原因为,客户端发起服务端连接时,会请求系统分配相关的文件句柄,在原代码中,仅仅判断是否连接成功,而未对连接失败进 行资源释放,从而造成文件句柄泄露。当总的文件句柄数超过系统设置值(ulimit -n  查看同一个进程允许的最大文件句柄数),则抛出异常“java.io.IOException: Too many open  files",导致无法创建新的连接,服务器挂掉。

      更改后的代码如下:

final  NioSocketConnector connector =  new  NioSocketConnector();    
2.        final  String[] result =  new  String[ 1 ];    
3.        connector.getFilterChain().addLast("codec" ,    
4.                new  ProtocolCodecFilter( new  ObjectSerializationCodecFactory()));    
5.        connector.setHandler(handler);   
6.   
7.        //设置超时     
8.        connector.setConnectTimeoutMillis(defaultConnectTimeOut);   
9.        ConnectFuture connectFuture = connector.connect(address);   
10.        connectFuture.awaitUninterruptibly();   //同步,等待,直到连接完成     
11.        if  (connectFuture.isDone()) {    
12.            if  (!connectFuture.isConnected()) {  //若在指定时间内没连接成功,则抛出异常     
13.                logger.info("fail to connect "  + logInfo);    
14.                connector.dispose();    //不关闭的话会运行一段时间后抛出,too many open files异常,导致无法连接     
15.   
16.                throw   new  Exception();    
17.            }   
18.        }


原帖地址:http://marsvaadin.iteye.com/blog/1698924

你可能感兴趣的:(网络通信应用框架)