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