數據庫故障oracle與防火墻
最近有兩次Oracle數據庫故障與防火墻有關。
最近有兩次Oracle數據庫故障與防火墻有關。這里的防火墻是硬件網絡防火墻,而不是軟件防火墻。
先說說簡單的。一個運行在Windows系統上的Oracle 9i,客戶端不能連接數據庫,但是用tnsping測試沒有問題。解決問題的辦法很簡單,但是我們仍然需要了解一下引起這個問題的原因。
這個問題首先得從客戶通通過監聽連接數據庫的整個過程說起,此處指專用服務器連接模式:
服務器上的監聽進程在1521端口上進行偵聽
客戶端發起一個數據庫連接請求
監聽進程fork一個Oracle服務器進程(Server Process),也可稱之為影子進程 (Shadow Process)。服務器進程選擇一個大于1024的端口號進行偵聽,監聽進程把這個端口號發回到客戶端,要求客戶端重新連接這個指定的端口。
客戶端重新連接監聽指定的新端口,也就是重新進行連接。
客戶端與Server Process直接對話,不再通過監聽,進行會話認證(登錄),執行SQL等等。
從上述過程可以看到,客戶端最終連接的端口實際上并不是1521。由于防火墻一般只開放了幾個端口,對Oracle數據庫只開放了1521端口,這樣在客戶端進行第二次連接時,不能通過防火墻,導致連接數據庫失敗。
值得慶幸的是,只有Windows平臺上的9i及以下版本的Oracle才會有這個問題。Oracle在Linux以及Unix平臺下,多個進程間可以對端口進行復用,Oracle Server Process仍然使用的是跟監聽進程一個端口(1521)。通過在linux使用strace跟蹤客戶端連接數據庫的過程可以發現,客戶端只連接了一次,并沒有進行第二次連接,與上面描述的流程相比已經發生了變化。在Windows平臺上,10g及以上版本的庫,也同樣利用端口復用,避免了這樣的問題。
那么Windows上運行的Oracle 9i怎么解決這個問題呢?答案很簡單,在Windows注冊表的\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOMEn(這里n指Oracle Home的序號,只有一個Oracle Home時是0)鍵下面增加一項USE_SHARED_SOCKET,其值為TRUE。然后重啟監聽及Oracle服務(注意要重啟Oracle的服務,而不僅僅是重啟數據庫),就可以解決此問題。實際上10g就是默認USE_SHARED_SOCKET為TRUE。
對于這種問題,或者是讓防火墻打開針對數據庫主機的所有端口訪問,也能解決。但是這種方案往往會被負責安全的人否決。
下面這個由防火墻導致的問題,就相對復雜一點了。
某個應用經常報ORA-3113錯誤,檢查發現ORA-3113來源于數據庫的一個db link。為了方便下面的描述,將應用直接連接的數據庫稱為DB_A,DB_A通過db link連接的對端的數據庫稱為DB_B。在DB_B主機上沒有發現任何有關的trace和日志,應用執行的SQL也是非常簡單的SELECT語句,返回的數據量也不大。但出錯的語句并不是固定的某一個SQL。在應用連接的數據庫DB_A上做ORA-3113 error stack的trace,也沒有發現有價值的東西。
導致ORA-3113錯誤的原因很多。大家可以參考ITPUB上的一篇貼子《ORA-03113錯誤分析》。
在這個ORA-3113錯誤的問題中,數據庫DB_B沒有任何日志,出現這種情況的一個很可能的原因是,DB_B上的Server Process已經中止,但又不是在執行SQL過程中出錯異常中止了,比如被KILL掉,網絡連接中斷等。被KILL掉這個原因,首先被排除,因為這個錯誤出現得很多,每天都有。詢問維護人員,稱也沒有進行過KILL操作。那么最大的可能性應該是網絡了。順著這條線索,我們在DB_A上用netstat -na命令檢查到DB_B的網絡連接,與DB_B中v$session中的會話進行比較,發現DB_A連接到DB_B的數據庫會話,比netstat 命令看到的網絡連接數少得多。
這是一個重大的突破。首先要懷疑的是防火墻。因為防火墻導致Oracle連接異常的情況非常多。訪問數據庫的DBA,這兩個數據庫分別在不同的業務網絡中,中間使用了Cisco的防火墻。請防火墻維護工程師檢查防火墻的設置,發現防火墻設置了TCP連接超時(這個術語是防火墻工程師告訴給我的,實際上我個人認為這個術語字面含義跟其實際的作用相差較大)設置為1小時。也就是,對于通過防火墻的所有TCP連接,如果在1小時內沒有任何活動,就會被防火墻拆除,這樣就會導致連接中斷。在拆除連接時,也不會向連接的兩端發送任何數據來通知連接已經拆除。
而出問題的業務系統,使用的高峰期是在正常的工作時間內,最高時會導致DB_A會產生數十個連接到DB_B。但是在業務低谷期或經過一個晚上,防火墻將拆除大部分甚至是所有的連接。而下一次使用時,應用通過連接池選擇DB_A中的一個會話,這個會話的db link之前已經連接到DB_B,但是網絡連接已經被防火墻拆除,但是這個會話并不知道,仍然會認為這個連接有效,結果試圖向DB_B提交SQL時,就出現了ORA-3113錯誤。
實際上,很多使用網絡連接的應用,可以使用稱之為KeepAlive的特性,來保持TCP連接的活動性。在打開一個連接時,通過setsockopt函數,設置socket為SO_KEEPALIVE,這樣,在OS層,如果一個TCP連接在指定的時間內沒有活動,會發送一個探測包到連接的對端,檢測連接的對端是否仍然存在。如果這個時間小于防火墻中設置的“超時”時間,防火墻就會檢查到連接中仍然有數據,就不會斷開這個連接。
操作系統中keep alive的相關設置,不同的系統有不同的設置方法。比如在Linux中,在sysctl中設置net.ipv4.tcp_keepalive_time = 120,表示探測時間為120秒,即2分鐘。在AIX中,通過no命令將tcp_keepidle參數設置為240,表示探測時間為120秒。注意AIX中這個參數的單位是1/2秒,而在Linux中是1秒。
還好Oracle提供了類似的機制。也就是DCD(Dead Conneciton Detection)。在$ORACLE_HOME/network/admin/sqlnet.ora文件中增加如下一行:
expire_time=NNN
這里NNN為分鐘數,Oracle數據庫會在會話IDLE時間超過這個指定的時間時,檢測這個會話的對端(即客戶端)是否還有效。避免客戶端由于異常退出,導致會話一直存在。
因此,我們可以通過在DB_B數據庫中的sqlnet.ora文件中設置expire_time來解決上面提到的ORA-3113問題。
先說說簡單的。一個運行在Windows系統上的Oracle 9i,客戶端不能連接數據庫,但是用tnsping測試沒有問題。解決問題的辦法很簡單,但是我們仍然需要了解一下引起這個問題的原因。
這個問題首先得從客戶通通過監聽連接數據庫的整個過程說起,此處指專用服務器連接模式:
服務器上的監聽進程在1521端口上進行偵聽
客戶端發起一個數據庫連接請求
監聽進程fork一個Oracle服務器進程(Server Process),也可稱之為影子進程 (Shadow Process)。服務器進程選擇一個大于1024的端口號進行偵聽,監聽進程把這個端口號發回到客戶端,要求客戶端重新連接這個指定的端口。
客戶端重新連接監聽指定的新端口,也就是重新進行連接。
客戶端與Server Process直接對話,不再通過監聽,進行會話認證(登錄),執行SQL等等。
從上述過程可以看到,客戶端最終連接的端口實際上并不是1521。由于防火墻一般只開放了幾個端口,對Oracle數據庫只開放了1521端口,這樣在客戶端進行第二次連接時,不能通過防火墻,導致連接數據庫失敗。
值得慶幸的是,只有Windows平臺上的9i及以下版本的Oracle才會有這個問題。Oracle在Linux以及Unix平臺下,多個進程間可以對端口進行復用,Oracle Server Process仍然使用的是跟監聽進程一個端口(1521)。通過在linux使用strace跟蹤客戶端連接數據庫的過程可以發現,客戶端只連接了一次,并沒有進行第二次連接,與上面描述的流程相比已經發生了變化。在Windows平臺上,10g及以上版本的庫,也同樣利用端口復用,避免了這樣的問題。
那么Windows上運行的Oracle 9i怎么解決這個問題呢?答案很簡單,在Windows注冊表的\HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\HOMEn(這里n指Oracle Home的序號,只有一個Oracle Home時是0)鍵下面增加一項USE_SHARED_SOCKET,其值為TRUE。然后重啟監聽及Oracle服務(注意要重啟Oracle的服務,而不僅僅是重啟數據庫),就可以解決此問題。實際上10g就是默認USE_SHARED_SOCKET為TRUE。
對于這種問題,或者是讓防火墻打開針對數據庫主機的所有端口訪問,也能解決。但是這種方案往往會被負責安全的人否決。
下面這個由防火墻導致的問題,就相對復雜一點了。
某個應用經常報ORA-3113錯誤,檢查發現ORA-3113來源于數據庫的一個db link。為了方便下面的描述,將應用直接連接的數據庫稱為DB_A,DB_A通過db link連接的對端的數據庫稱為DB_B。在DB_B主機上沒有發現任何有關的trace和日志,應用執行的SQL也是非常簡單的SELECT語句,返回的數據量也不大。但出錯的語句并不是固定的某一個SQL。在應用連接的數據庫DB_A上做ORA-3113 error stack的trace,也沒有發現有價值的東西。
導致ORA-3113錯誤的原因很多。大家可以參考ITPUB上的一篇貼子《ORA-03113錯誤分析》。
在這個ORA-3113錯誤的問題中,數據庫DB_B沒有任何日志,出現這種情況的一個很可能的原因是,DB_B上的Server Process已經中止,但又不是在執行SQL過程中出錯異常中止了,比如被KILL掉,網絡連接中斷等。被KILL掉這個原因,首先被排除,因為這個錯誤出現得很多,每天都有。詢問維護人員,稱也沒有進行過KILL操作。那么最大的可能性應該是網絡了。順著這條線索,我們在DB_A上用netstat -na命令檢查到DB_B的網絡連接,與DB_B中v$session中的會話進行比較,發現DB_A連接到DB_B的數據庫會話,比netstat 命令看到的網絡連接數少得多。
這是一個重大的突破。首先要懷疑的是防火墻。因為防火墻導致Oracle連接異常的情況非常多。訪問數據庫的DBA,這兩個數據庫分別在不同的業務網絡中,中間使用了Cisco的防火墻。請防火墻維護工程師檢查防火墻的設置,發現防火墻設置了TCP連接超時(這個術語是防火墻工程師告訴給我的,實際上我個人認為這個術語字面含義跟其實際的作用相差較大)設置為1小時。也就是,對于通過防火墻的所有TCP連接,如果在1小時內沒有任何活動,就會被防火墻拆除,這樣就會導致連接中斷。在拆除連接時,也不會向連接的兩端發送任何數據來通知連接已經拆除。
而出問題的業務系統,使用的高峰期是在正常的工作時間內,最高時會導致DB_A會產生數十個連接到DB_B。但是在業務低谷期或經過一個晚上,防火墻將拆除大部分甚至是所有的連接。而下一次使用時,應用通過連接池選擇DB_A中的一個會話,這個會話的db link之前已經連接到DB_B,但是網絡連接已經被防火墻拆除,但是這個會話并不知道,仍然會認為這個連接有效,結果試圖向DB_B提交SQL時,就出現了ORA-3113錯誤。
實際上,很多使用網絡連接的應用,可以使用稱之為KeepAlive的特性,來保持TCP連接的活動性。在打開一個連接時,通過setsockopt函數,設置socket為SO_KEEPALIVE,這樣,在OS層,如果一個TCP連接在指定的時間內沒有活動,會發送一個探測包到連接的對端,檢測連接的對端是否仍然存在。如果這個時間小于防火墻中設置的“超時”時間,防火墻就會檢查到連接中仍然有數據,就不會斷開這個連接。
操作系統中keep alive的相關設置,不同的系統有不同的設置方法。比如在Linux中,在sysctl中設置net.ipv4.tcp_keepalive_time = 120,表示探測時間為120秒,即2分鐘。在AIX中,通過no命令將tcp_keepidle參數設置為240,表示探測時間為120秒。注意AIX中這個參數的單位是1/2秒,而在Linux中是1秒。
還好Oracle提供了類似的機制。也就是DCD(Dead Conneciton Detection)。在$ORACLE_HOME/network/admin/sqlnet.ora文件中增加如下一行:
expire_time=NNN
這里NNN為分鐘數,Oracle數據庫會在會話IDLE時間超過這個指定的時間時,檢測這個會話的對端(即客戶端)是否還有效。避免客戶端由于異常退出,導致會話一直存在。
因此,我們可以通過在DB_B數據庫中的sqlnet.ora文件中設置expire_time來解決上面提到的ORA-3113問題。
責任編輯:和碩涵
免責聲明:本文僅代表作者個人觀點,與本站無關。其原創性以及文中陳述文字和內容未經本站證實,對本文以及其中全部或者部分內容、文字的真實性、完整性、及時性本站不作任何保證或承諾,請讀者僅作參考,并請自行核實相關內容。
我要收藏
個贊
-
發電電力輔助服務營銷決策模型
2019-06-24電力輔助服務營銷 -
繞過安卓SSL驗證證書的四種方式
-
網絡何以可能
2017-02-24網絡