背景介紹:
原環境:
服務器: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的數據庫連接在沒有數據交換的情況下,由服務器端自動發出探測的數據報,使得防火牆不再認為數據庫連接是空閑的連接。
目前等待中;
(網絡太差了,外包傷不起啊)