背景: 前天线上的tomcat突然挂了,一看原来网络连接超过了操作系统的限制
其实tomcat的压力也不大,并发也就20-30,怎么会造成这种情况,仔细观察发现好多
TCP连接Close_Wait, 这些连接都指向我们邮件中的附件资源,原来是我们发送带附件的邮件造成的
我们在发送邮件的程序中使用了URLDataSource,我在本地测试的时候也发现,在使用URLDataSource的情况下,确实会造成连接不关闭。
通过查看javamail的源代码,发现javamail也并非完全不关闭连接,在使用URLDataSource的时候会打开资源地址请求类型,也会通过流打开真正的资源,javamail获取资源后通过关闭流也关闭了资源的连接,但是获取资源类型的时候并未关闭连接
看看URLDataSource的源代码
- publicStringgetContentType(){
- Stringtype=null;
- try{
- if(url_conn==null)
- url_conn=url.openConnection();
- }catch(IOExceptione){}
- if(url_conn!=null)
- type=url_conn.getContentType();
- if(type==null)
- type="application/octet-stream";
- returntype;
- }
URLDataSource并没有关闭类型连接的接口,所以一旦getContentType就没法关闭了,还好
javamail 的URLDataSource还是很好扩展的,解决办法如下- publicclassXXURLDataSourceextendsURLDataSource{
- publicXXURLDataSource(URLarg0){
- super(arg0);
- //TODOAuto-generatedconstructorstub
- }
- publicStringgetContentType(){
- Stringtype=null;
- java.net.HttpURLConnectionurl_conn=null;
- try{
- //if(url_conn==null)
- url_conn=(java.net.HttpURLConnection)this
- .getURL().openConnection();
- }catch(IOExceptione){
- }
- if(url_conn!=null){
- type=url_conn.getContentType();
- url_conn.disconnect();
- }
- if(type==null)
- type="application/octet-stream";
- returntype;
- }
- }
(这段程序仅支持
http 的资源类型,其他类型资源请自行解决)产生一个类,继承URLDataSource ,并覆盖getContentType函数,然后在调用的地方把
URLDataSource 变为XXURLDataSource即可,本地测试没有问题,然后放在线上测试
发了3000封带附件的程序,系统fd一度高达3100+,后来在半小时内,fd逐渐回收,fd降到数百的正常水平,改造算是基本成功了