防止防火墻導致的數(shù)據(jù)庫空閑連接斷開問題的方法,相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。
創(chuàng)新互聯(lián)是一家專業(yè)提供東營區(qū)企業(yè)網(wǎng)站建設,專注與成都網(wǎng)站設計、網(wǎng)站建設、H5場景定制、小程序制作等業(yè)務。10年已為東營區(qū)眾多企業(yè)、政府機構(gòu)等服務。創(chuàng)新互聯(lián)專業(yè)網(wǎng)絡公司優(yōu)惠進行中。
ERROR [com.alibaba.druid.util.JdbcUtils] - close connection error java.sql.SQLRecoverableException: IO Error: Broken pipe at oracle.jdbc.driver.T4CConnection.logoff(T4CConnection.java:556) at oracle.jdbc.driver.PhysicalConnection.close(PhysicalConnection.java:3984) at com.alibaba.druid.filter.FilterChainImpl.connection_close(FilterChainImpl.java:167) at com.alibaba.druid.filter.stat.StatFilter.connection_close(StatFilter.java:254) at com.alibaba.druid.filter.FilterChainImpl.connection_close(FilterChainImpl.java:163) at com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl.close(ConnectionProxyImpl.java:115) at com.alibaba.druid.util.JdbcUtils.close(JdbcUtils.java:79) at com.alibaba.druid.pool.DruidDataSource.discardConnection(DruidDataSource.java:965) at com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:932) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4534) at com.alibaba.druid.filter.stat.StatFilter.dataSource_getConnection(StatFilter.java:661) at com.alibaba.druid.filter.FilterChainImpl.dataSource_connect(FilterChainImpl.java:4530) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:884) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:876) at com.alibaba.druid.pool.DruidDataSource.getConnection(DruidDataSource.java:92)
java.net.SocketException: Broken pipe是什么意思呢?
其實就是與數(shù)據(jù)庫建立的tcp連接因為某些原因斷開了,而導致了“管道破裂”。一般數(shù)據(jù)庫連接池會與數(shù)據(jù)庫保持長連接,在需要的時候省去建立連接的過程,直接使用,而為什么這些空閑的連接會被斷開呢?被誰斷開了?
后來和同事討論的過程中得知別的項目組也發(fā)生過類似的情況,而他們和這個項目的共同之處就在于服務都是在DMZ區(qū),外網(wǎng)可訪問,而數(shù)據(jù)庫在內(nèi)網(wǎng),需要通過防火墻才能訪問到數(shù)據(jù)庫。于是去找負責維護網(wǎng)絡、防火墻的同事了解,原來防火墻有一個TCP超時時間,目前設置的為半小時,其意義是,對于通過防火墻的所有TCP連接,如果在半小時內(nèi)沒有任何活動,就會被防火墻拆除,這樣就會導致連接中斷。在拆除連接時,也不會向連接的兩端發(fā)送任何數(shù)據(jù)來通知連接已經(jīng)拆除。
這是一個臨時解決方法,比如將防火墻的連接超時時間調(diào)整為8小時,這樣可以盡量避免空閑連接的切斷,但無法完全避免,因為無法預計連接會被空閑多久,如果你的系統(tǒng)不是總有人訪問的話,那么連接遲早會因為空閑而被切斷,導致一些不可預計的問題,而調(diào)大超時時間只是緩解而已
tcp的keepalive,其實就是用來保持tcp連接的,其原理簡單說就是如果一個TCP連接在指定的時間內(nèi)沒有任何活動,會發(fā)送一個探測包到連接的對端,檢測連接的對端是否仍然存在,如果對端一定時間內(nèi)仍沒有對探測的響應,會再次發(fā)送探測包,發(fā)送幾次后,仍然沒有響應,就認為連接已經(jīng)失效,關閉本地連接。
tcp keepalive并不是默認開啟的,在開發(fā)程序時可以設置tcp keepalive為true,這樣tcp連接在一定時間內(nèi)沒有任何數(shù)據(jù)報文傳輸則啟動探測,這個時間一般是操作系統(tǒng)規(guī)定,Linux系統(tǒng)中可以通過設置net.ipv4.tcp_keepalive_time
來修改,默認是7200秒,即2小時。當然在編程時也可以設置這個時間用于當前socket,但是Java的Socket API中好像只有設置keepalive=true,并沒法設置tcp_keepalive_time
當設置了tcp keepalive之后,只要tcp探測包發(fā)送的時間小于防火墻的連接超時時間,防火墻就會檢查到連接中仍然有數(shù)據(jù)傳輸,就不會斷開這個連接。
使用JDBC創(chuàng)建的數(shù)據(jù)庫tcp連接是沒有設置keepalive的,這點可以通過Linux的netstat或ss命令在數(shù)據(jù)庫客戶端(即應用端)驗證
使用命令netstat -ano或 ss -ano,其中參數(shù)o都是顯示timer計時器,timer計時器在連接建立狀態(tài)下可以對連接?;钣嫊r
netstat命令對沒有開啟keepalive的tcp連接顯示為:off (0.00/0/0)
ss命令對沒有keepalive的tcp連接,不會顯示timer計時器
Oracle提供了類似tcp keepalive的機制,也就是DCD(Dead Conneciton Detection)。在$ORACLE_HOME/network/admin/sqlnet.ora文件中增加如下一行:
sqlnet.expire_time=NNN
這里NNN為分鐘數(shù),Oracle數(shù)據(jù)庫會在會話IDLE時間超過這個指定的時間時,檢測這個會話的對端(即客戶端)是否還有效。避免客戶端由于異常退出,導致會話一直存在。
同樣的如果DCD的時間比防火墻切斷空閑連接的時間短,連接也可以一直保持
以上幾種方法要么是利用tcp連接keepalive特性,要么是采用數(shù)據(jù)庫端的空閑連接檢測,我們的程序中也可以主動做這種心跳檢測
Druid數(shù)據(jù)庫連接池從1.0.28開始,添加了druid.keepAlive屬性,默認關閉
打開druid.keepAlive之后,當連接池空閑時,池中的minIdle數(shù)量以內(nèi)的連接,空閑時間超過minEvictableIdleTimeMillis,則會執(zhí)行keepAlive操作,即執(zhí)行druid.validationQuery指定的查詢SQL,一般為select * from dual,只要minEvictableIdleTimeMillis設置的小于防火墻切斷連接時間,就可以保證當連接空閑時自動做保活檢測,不會被防火墻切斷
看完上述內(nèi)容,你們掌握防止防火墻導致的數(shù)據(jù)庫空閑連接斷開問題的方法的方法了嗎?如果還想學到更多技能或想了解更多相關內(nèi)容,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!