别让防火墙中断数据库连接
背景介绍:
原环境:
服务器:jboss5
jdk:1.5
防火墙:没有设置
新环境:
服务器:jboss7
jdk:1.6
防火墙:需要设置
防火墙问题:
问题1:
跨区连接报表平台,系统从报表平台下载文件时用的是icas,看了看代码:
它的默认端口是8821,有两种模式:主动模式和被动模式,原来用的是主动模式;
原来没有防火墙当然不是问题,加了防火墙之后,点击下载后会发送下载的请求数据到报表服务器,报表服务器会返回数据,但是icas用的是主动模式,所以默认不接受返回数据,导致下载不了;(这个问题猜测是这样,后面会查一下这方面的资料,补充确认;话说icas的资料呵呵);
问题2:
跨区连接核心系统:(历史原因)从核心下载文件或上传文件到核心用的是TFTP:
TFTP的默认端口是69,这个应该只是测试连通性的端口(求大神指教),TFTP是基于UDP协议的,UDP协议是数据报协议,短连接,无固定端口;
由于传输文件时没有固定的端口,也就是说传输文件时用到的端口范围是从(1024-65535),这个范围大了,一般防火墙只是对某个ip地址开几个端口,这下等于要全开了,不设防,最终一番扯皮之后,还是开any了;
问题3:
系统用的框架是spring+ibatis,连接池用的是dbcp,由于前面已经因为防火墙的存在出了好几个连接问题,一直有某种担心,上生产后果然。。。
刚上线时一切正常,然后到周一客户开始登陆系统,中间没有听到客户反映什么问题;下班时检查日志发现了问题,连接一个数据时,报数据库已关闭:
nested exception is org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; Already closed.; nested exception is java.sql.SQLException: Already closed.
Caused by: org.springframework.jdbc.UncategorizedSQLException: SqlMapClient operation; uncategorized SQLException for SQL []; SQL state [null]; error code [0]; Already closed.; nested exception is java.sql.SQLException: Already closed.
Caused by: java.sql.SQLException: Already closed.
at org.apache.commons.dbcp.PoolableConnection.close(PoolableConnection.java:77)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.close(PoolingDataSource.java:180)
at org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(Unknown Source)
at org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy$TransactionAwareInvocationHandler.invoke(Unknown Source)
at $Proxy14.close(Unknown Source)
at sun.reflect.GeneratedMethodAccessor74.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.ibatis.common.jdbc.logging.ConnectionLogProxy.invoke(ConnectionLogProxy.java:62)
at $Proxy11.close(Unknown Source)
at com.ibatis.sqlmap.engine.transaction.external.ExternalTransaction.close(ExternalTransaction.java:82)
at com.ibatis.sqlmap.engine.transaction.TransactionManager.end(TransactionManager.java:110)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.endTransaction(SqlMapExecutorDelegate.java:776)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.endTransaction(SqlMapSessionImpl.java:137)
at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.endTransaction(SqlMapClientImpl.java:115)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.autoEndTransaction(SqlMapExecutorDelegate.java:860)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:568)
at com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForObject(SqlMapExecutorDelegate.java:536)
at com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForObject(SqlMapSessionImpl.java:93)
at com.ibatis.sqlmap.engine.impl.SqlMapClientImpl.queryForObject(SqlMapClientImpl.java:70)
at org.springframework.orm.ibatis.SqlMapClientTemplate$1.doInSqlMapClient(Unknown Source)
... 34 common frames omitted
分析之后,觉得可能是应用系统长时间不连接数据库后,防火墙自动中断了;
后面加了一个参数:<param name="validationQuery">SELECT 1 FROM dual</param>,用来每个一段时间去查一下数据库,用的是oracle数据库,(不同的数据库语句不一样);
重启之后果然连接上了,但是到了晚上之后发现又连接不上了,一番测试:有的能连上,有的连不上;分析之后重启,明天再看日志;
隔天经历发我一篇文章:感觉问题就在这,果断复制粘贴:
别让防火墙中断数据库连接 通常的Web应用都是无状态的连接,一般来说对于防火墙是非常友好的。但是,大多数JavaEE应用服务器都有连接池的概念。为了提高性能,
应用服务器会预先打开并保持一些和后台数据库服务器、LDAP服务器或其他服务器的连接。这些连接通常会将TCP的连接永久保持,除非发生了
意外的情况。
我有几个项目发生的问题都是应用服务器和数据库之间由于安全级别的问题,设有不同的防火墙。在系统运行的时候,偶尔会发生数据库连接无法
获得的错误(在系统很闲的时候)。客户怀疑应用服务器的不稳定性。通过各种工具的分析(snoop),发现当应用服务器的数据库连接出现问题
的时候,数据库这端没有任何问题,所有的Session连接都在,但是从应用服务器发过来的TCP请求没有到达数据库服务器。是中间的防火墙阻断
了数据库的连接。在一个空闲的 TCP 连接上,可以很长时间没有任何的数据流,许多 TCP/IP 的初学者都对此感到惊奇。
因此当数据库连接长时间不用(这种情况很常见,例如连接池中有10个连接,由于负载很小,一直只用到前几个)。一般来说,防火墙软件都会
定时检查空闲的连接,并将它们阻断,来保证一些异常的中断连接被清除。
这样,我们对数 据库连接问题的原因找到了,由于空闲的数据库连接长时间不用被防火墙给阻断是主要的原因。被阻断了的数据库连接在使用的
时候不会自动重新连接吗?大多数应 用服务器所使用的专业的数据库连接池都会有自动重新连接来解决这个问题。也有一些客户使用自己的连接池,或者一些简单的开源的方案,没有自动重联的功能, 导致应用不可用。 就算有的连接池能够自动重连中断的连接,也不会时时刻刻都去检查这些在连接池中的连接是否被可用。
因为这种检查非常消耗时间,还会影响应用,因此会每隔几分钟检查一次。在间隔时间内发生的连接中断仍然会引起系统的错误。
另外的解决方案 就是从数据库服务器端进行配置,保证连接的畅通。例如在Oracle中可以设置SQLNET.EXPIRE_TIME小于防火墙的中断时间,
就能够是 Oracle的数据库连接在没有数据交换的情况下,由服务器端自动发出探测的数据报,使得防火墙不再认为数据库连接是空闲的连接。
目前等待中;
(网络太差了,外包伤不起啊)