生活随笔
收集整理的這篇文章主要介紹了
防火墙、DCD与TCP Keep alive
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
在以前我寫的一篇文章《Oracle與防火墻》中提到,網絡防火墻會切斷長時間空閑的TCP連接,這個空閑時間具體多長可以在防火墻內部進行設置。防火墻切斷連接之后,會有下面的可能:
- 切斷連接之前,連接對應的Oracle會話正在執行一個耗時特別長的SQL,比如存儲過程而在此過程中沒有任何數據輸出到客戶端,這樣當SQL執行完成之后,向客戶端返回結果時,如果TCP連接已經被防火墻中斷,這時候顯然會出現錯誤,連接中斷,那么會話也就會中斷。但是客戶端還不知道,會一直處于等待服務器返回結果的狀態。
- 切斷連接之前,Oracle會話一直處于空閑狀態,在防火墻中斷之后,客戶端向Oracle服務器提交SQL時,由于TCP連接已經中斷,這時客戶端偵測到連接中斷,那么客戶端就會報ORA-3113/ORA-3114這類錯誤,然后會話中斷。但是在Oracle服務器端,會話一直在處于等待客戶端消息的狀態。
- 當然,如果服務器和客戶端都一直閑著,沒有任何消息往來,那么客戶端和客戶端的會話就一直存在,直到客戶端發送消息即提交SQL到Oracle服務器。
從上面的前面2種情況來看,防火墻切斷數據庫TCP連接,引起的后果就會有:
- 客戶端報ORA-3113/3114錯誤,對這于長連接的后臺應用不是個好事,特別是對那種C/C++開發的后臺應用沒有重連機制,就會出現問題或者程序退出。如果應用在一個較長的時間內沒有任何活動,而這個時間超過了防火墻的設置,那應用的連接被中斷。
- 對于有連接池或重連機制的應用,如果連接池過大,導致空閑連接過多,或者是防火墻的連接斷開時間過短同時應用太閑,那么連接頻繁地被中斷,而在數據庫服務器端,則連接越來越多,即會話數越來越多,甚至最終超過了數據為最大連接數。
- 其他一些影響,比如你在跑一個腳本而長時間沒有輸出,結果防火墻切斷了連接,你之前的工作就白做,當然這些影響范圍都較小。
那么如何防止出現以上的問題? 對于沒有重連機制的長連接應用,臨時的解決辦法是調大防火墻的連接切斷時長;或者應用端在閑時定期執行一條類似于select 1 from dual這樣的SQL;或者在Oracle服務端開啟DCD功能,而DCD(死連接檢測,即Dead Connection Detection)的時間長度短于防火墻的連接切斷時長;或者使用操作系統的tcp keep-alive功能。對于有重連機制或有連接池的應用,為了避免數據庫端連接數滿,可以使用DCD或tcp keep-alive功能,如果DCD或TCP keep-alive的時間短于防火墻連接切斷時長,那么連接將不會中斷,因為防火墻視連接為活動狀態(不過按MOS文檔的說法,DCD的包有可能被防火墻忽略,即用DCD使連接保持活動狀態可能沒有作用)。而如果DCD或TCP keep-alive的時間長于防火墻連接切斷時長,那么連接被中斷的會話和進程將得到清理。
這里簡單介紹一下TCP keep-alive,顧名思議,就是讓TCP連接保持存活狀態,這是由TCP協議層實現的功能,也是在TCP連接空閑時間超過設置的時間,就會發送探測包,因此,這個功能跟Oracle的DCD是極為類似的,所不同的是,這是由協議層實現的功能,是不能通過trace應用進程來跟蹤包的發送。
理論是完美的,而現實差距越很遠。
下面是一個有關的案例。一套運行在AIX 5.3上的RAC數據庫,數據庫版本為10.2.0.4,這套數據庫在sqlnet.ora文件中有設置sqlnet.expire_time=5,后果卻是,數據庫的連接數過幾天就要滿一次,防火墻設置的時間是8小時,也就是說只會切斷空閑時間超過8小時的連接,這個時間已經足夠長,晚上系統太閑,總會有部分連接空閑時間過長,但是由于設置了DCD,連接應該不會被防火墻切斷,而即使防火墻切斷了連接,那么在DCD的作用下,數據庫服務器端的會話和進程也應該被清理才是,即使DCD不起作用,那TCP keep-alive也應該起作用才是,那為什么會話和進程數越來越多,甚至達到了最大進程數或會話數呢?
檢查應用服務器(weblogic)的連接池,并核對應用服務器到數據庫的TCP連接,發現連接池監控中的連接數量并不多,而對比應用服務器上看到的到數據庫數據庫的TCP連接數量和數據庫數據器上看到的應用服務器建立過來的TCP連接數量,二者之間差距非常大,前者遠遠小于后者,就是說,大量的連接已經被切斷,應用服務器的連接已經退出,但是數據庫端的連接還沒有釋放。從weblogic的日志來看,經常出現類似于連接失效并建立新的數據庫連接這樣的信息。
DCD為什么沒有起作用,是不是DCD的BUG?DCD的確是有很多BUG,但是完全不工作的BUG應該是很少的。將sqlnet.expire_time設為1,5以及其他值,都不起作用,甚至重啟過主機都沒有起作用(當然并不是專門為了DCD而重啟主機)。
使用truss命令來跟蹤Oracle進程:
view plain copy to clipboard print ?
?? SQL>?host ?? $?truss?-p?828090 ?? kread(0,?0x0000000000000000,?0)?(sleeping...) ?? ...很長時間沒有任何反應... ?? ^CPstatus:?process?is?not?stopped ?? $? ?? $?exit ?? ?? SQL>?oradebug?setospid?828090 ?? Oracle?pid:?247,?Unix?process?pid:?828090,?image:?oracle@db2 ?? SQL>?oradebug?short_stack? ?? ksdxfstk+002c<-ksdxcb+04e4<-sspuser+0074<-000044C0<-nttrd+0120<-nsprecv+07a0<-nsrdr+0114<-nsdo+1710<-nsbrecv+0040<-nioqrc+04a8<-opikndf2+0688<-opitsk+08a8<-opiino+0990<-opiodr+0ae0<-opidrv+0484<-sou2o+0090<-opimai_real+01bc<-main+0098<-__start+0098 ?? SQL>??oradebug?short_stack ?? ksdxfstk+002c<-ksdxcb+04e4<-sspuser+0074<-000044C0<-nttrd+0120<-nsprecv+07a0<-nsrdr+0114<-nsdo+1710<-nsbrecv+0040<-nioqrc+04a8<-opikndf2+0688<-opitsk+08a8<-opiino+0990<-opiodr+0ae0<-opidrv+0484<-sou2o+0090<-opimai_real+01bc<-main+0098<-__start+0098?? [sql]? view plain copy
SQL>?host?? $?truss?-p?828090?? kread(0,?0x0000000000000000,?0)?(sleeping...)?? ...很長時間沒有任何反應...?? ^CPstatus:?process?is?not?stopped?? $??? $?exit?? ?? SQL>?oradebug?setospid?828090?? Oracle?pid:?247,?Unix?process?pid:?828090,?image:?oracle@db2?? SQL>?oradebug?short_stack??? ksdxfstk+002c<-ksdxcb+04e4<-sspuser+0074<-000044C0<-nttrd+0120<-nsprecv+07a0<-nsrdr+0114<-nsdo+1710<-nsbrecv+0040<-nioqrc+04a8<-opikndf2+0688<-opitsk+08a8<-opiino+0990<-opiodr+0ae0<-opidrv+0484<-sou2o+0090<-opimai_real+01bc<-main+0098<-__start+0098?? SQL>??oradebug?short_stack?? ksdxfstk+002c<-ksdxcb+04e4<-sspuser+0074<-000044C0<-nttrd+0120<-nsprecv+07a0<-nsrdr+0114<-nsdo+1710<-nsbrecv+0040<-nioqrc+04a8<-opikndf2+0688<-opitsk+08a8<-opiino+0990<-opiodr+0ae0<-opidrv+0484<-sou2o+0090<-opimai_real+01bc<-main+0098<-__start+0098?? 沒有看到DCD起任何作用的跡象,使用truss跟蹤其他多個空閑Oracle也是如此。
那么TCP keep-alive呢,怎么樣來判斷有沒有起作用?在AIX上其答案是使用kdb(這個需要root用戶權限)。
在筆記本電腦上使用sqlplus連接到數據庫,在數據庫主機上使用netstat -Aan | grep 1521 | grep “你的IP地址”,以獲得sqlplus連接的TCP連接信息,顯示的第1列是一串16數據,然后使用kdb:
view plain copy to clipboard print ?
#kdb? ?? The?specified?kernel?file?is?a?64-bit?kernel ?? Preserving?1418178?bytes?of?symbol?table?? First?symbol?__mulh ?? ???????????START??????????????END?<name?> ?? 0000000000001000?0000000003E5C050?start+000FD8 ?? F00000002FF47600?F00000002FFDC940?__ublock+000000 ?? 000000002FF22FF4?000000002FF22FF8?environ+000000 ?? 000000002FF22FF8?000000002FF22FFC?errno+000000 ?? F100070F00000000?F100070F10000000?pvproc+000000 ?? F100070F10000000?F100070F18000000?pvthread+000000 ?? PFT: ?? PVT: ?? id....................0002 ?? raddr.....0000000002000000?eaddr.....F200800090000000 ?? size..............00080000?align.............00001000 ?? valid..1?ros....0?fixlmb.1?seg....0?wimg...2 ?? Command?enhancement?entry?point?is?called. ?? ?? ?Welcome?to?VXDRV?subcommands? ?? Command?enhancement?entry?for?vxodmdb?called.called. ?? ?? ?Welcome?to?vxdrv?subcommands? ?? (0)>?sockinfo?f100060009b04398?tcpcb?|?egrep?"KEEP|opts"?? ????t_timer.......?00000000?(TCPT_KEEP) ?? ????timewait.prv@0000000000000000??inp_v6opts??@0000000000000000?? ?? ????opts........?0004?(REUSEADDR)????? [sql]? view plain copy
#kdb??? The?specified?kernel?file?is?a?64-bit?kernel?? Preserving?1418178?bytes?of?symbol?table?? First?symbol?__mulh?? ???????????START??????????????END?<name?>?? 0000000000001000?0000000003E5C050?start+000FD8?? F00000002FF47600?F00000002FFDC940?__ublock+000000?? 000000002FF22FF4?000000002FF22FF8?environ+000000?? 000000002FF22FF8?000000002FF22FFC?errno+000000?? F100070F00000000?F100070F10000000?pvproc+000000?? F100070F10000000?F100070F18000000?pvthread+000000?? PFT:?? PVT:?? id....................0002?? raddr.....0000000002000000?eaddr.....F200800090000000?? size..............00080000?align.............00001000?? valid..1?ros....0?fixlmb.1?seg....0?wimg...2?? Command?enhancement?entry?point?is?called.?? ?? ?Welcome?to?VXDRV?subcommands??? Command?enhancement?entry?for?vxodmdb?called.called.?? ?? ?Welcome?to?vxdrv?subcommands??? (0)>?sockinfo?f100060009b04398?tcpcb?|?egrep?"KEEP|opts"?? ????t_timer.......?00000000?(TCPT_KEEP)?? ????timewait.prv@0000000000000000??inp_v6opts??@0000000000000000???? ????opts........?0004?(REUSEADDR)????? 可以看到,這個TCP連接沒有KEEPALIVE選項(屬性),keep-alive對應的timer(TCPT_KEEP)數值為0,表示沒有設置timer時間。
會不會是DCD功能屏蔽了TCP keep-alive?
將sqlnet.ora中expire_time設置去掉,然后重復上述步驟,這次有了變化:
view plain copy to clipboard print ?
#kdb?? ?? The?specified?kernel?file?is?a?64-bit?kernel ?? Preserving?1418178?bytes?of?symbol?table?? First?symbol?__mulh ?? ???????????START??????????????END?<name?> ?? 0000000000001000?0000000003E5C050?start+000FD8 ?? F00000002FF47600?F00000002FFDC940?__ublock+000000 ?? 000000002FF22FF4?000000002FF22FF8?environ+000000 ?? 000000002FF22FF8?000000002FF22FFC?errno+000000 ?? F100070F00000000?F100070F10000000?pvproc+000000 ?? F100070F10000000?F100070F18000000?pvthread+000000 ?? PFT: ?? PVT: ?? id....................0002 ?? raddr.....0000000002000000?eaddr.....F200800090000000 ?? size..............00080000?align.............00001000 ?? valid..1?ros....0?fixlmb.1?seg....0?wimg...2 ?? Command?enhancement?entry?point?is?called. ?? ?? ?Welcome?to?VXDRV?subcommands? ?? Command?enhancement?entry?for?vxodmdb?called.called. ?? ?? ?Welcome?to?vxdrv?subcommands? ?? (0)>?sockinfo?f100060009c1b398?tcpcb?|?egrep?"KEEP|opts"?? ????t_timer.......?00000464?(TCPT_KEEP) ?? ????timewait.prv@0000000000000000??inp_v6opts??@0000000000000000?? ?? ????opts........?000C?(REUSEADDR|KEEPALIVE)?? [sql]? view plain copy
#kdb???? The?specified?kernel?file?is?a?64-bit?kernel?? Preserving?1418178?bytes?of?symbol?table?? First?symbol?__mulh?? ???????????START??????????????END?<name?>?? 0000000000001000?0000000003E5C050?start+000FD8?? F00000002FF47600?F00000002FFDC940?__ublock+000000?? 000000002FF22FF4?000000002FF22FF8?environ+000000?? 000000002FF22FF8?000000002FF22FFC?errno+000000?? F100070F00000000?F100070F10000000?pvproc+000000?? F100070F10000000?F100070F18000000?pvthread+000000?? PFT:?? PVT:?? id....................0002?? raddr.....0000000002000000?eaddr.....F200800090000000?? size..............00080000?align.............00001000?? valid..1?ros....0?fixlmb.1?seg....0?wimg...2?? Command?enhancement?entry?point?is?called.?? ?? ?Welcome?to?VXDRV?subcommands??? Command?enhancement?entry?for?vxodmdb?called.called.?? ?? ?Welcome?to?vxdrv?subcommands??? (0)>?sockinfo?f100060009c1b398?tcpcb?|?egrep?"KEEP|opts"?? ????t_timer.......?00000464?(TCPT_KEEP)?? ????timewait.prv@0000000000000000??inp_v6opts??@0000000000000000???? ????opts........?000C?(REUSEADDR|KEEPALIVE)?? 可以看到,這個TCP連接已經有了KEEPALIVE選項(屬性),同時keep-alive timer為16進制數464,即十進制1124,表示還有562秒(timer這里的時間以半秒為單位)就會發送keep-alive探測包。
反復通過加上DCD設置和去掉DCD設置進行測試,發現只要一加上DCD功能,那么Oracle進程就不會為TCP連接設置keep-alive選項(屬性),反之則會設置keep-alive。從這里很明顯地看出來,DCD功能開啟后,不但沒有起作用,還關閉了TCP keep-alive功能。
對于這套系統,最后去掉了DCD設置,并將所有的空閑連接清理掉,經過多天的觀察,系統的連接數一直保持穩定,與應用服務器的實際連接數保持一致。
那是不是啟用了DCD之后,TCP keep-alive就會被關閉,這里不能貿然下定論,不同的版本、不同的平臺或許有差異,至少我一個同事在Linux上測試時,tcp keep-alive是共存的。
在診斷處理這個案例的過程之中,不得不提到另外一點,寫在此處,與大家分享。在診斷問題的初期階段,詢問系統維護人員(通常連應用和數據庫一起維護),應用服務器和數據庫之間是否有防火墻,如果有,是怎么樣設置的TCP連接斷開時間。而維護人員最開始的回答是沒有防火墻。從表面上看,也應該是沒有防火墻。數據庫服務器其中一個IP地址是192.168.8.42,而兩臺應用服務器服務器的IP地址是192.168.8.201和192.168.8.202,咋一看是在同一網段,中間應該不會有防火墻。然而仔細檢查相關數據:
$ifconfig?-a ?? ....省略部分輸出.... ?? en4:?flags=5e080867,c0<up?,BROADCAST,DEBUG,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,CHECKSUM_OFFLOAD(ACTIVE),PSEG,LARGESEND,CHAIN> ?? ????????inet?192.168.8.42?netmask?0xffffff80?broadcast?192.168.8.127 ?? ????????inet?192.168.8.43?netmask?0xffffff80?broadcast?192.168.8.127 ?? ?????????tcp_sendspace?131072?tcp_recvspace?65536?rfc1323?0?? [sql]? view plain copy
$ifconfig?-a?? ....省略部分輸出....?? en4:?flags=5e080867,c0<up?,BROADCAST,DEBUG,NOTRAILERS,RUNNING,SIMPLEX,MULTICAST,GROUPRT,64BIT,CHECKSUM_OFFLOAD(ACTIVE),PSEG,LARGESEND,CHAIN>?? ????????inet?192.168.8.42?netmask?0xffffff80?broadcast?192.168.8.127?? ????????inet?192.168.8.43?netmask?0xffffff80?broadcast?192.168.8.127?? ?????????tcp_sendspace?131072?tcp_recvspace?65536?rfc1323?0?? 可以看到,實際上數據庫跟應用服務器是在不同的子網之中。這里子網掩碼為0xffffff80,也就是我們通常寫的子網掩碼255.255.255.128,這樣0-127為一個子網,128-255為一個子網(當然子網的第1個和最后一個地址都是不能使用的)。那么最后一個數字為201和202的兩個IP地址顯然就在第2個子網中,子網之間仍然需要有路由功能的網絡設備,那么在之間有防火墻也是有可能的。用上面的方法去檢查應用服務器的網絡配置,發現其被劃在了更小的子網之中。系統維護人員最終確認應用服務器和數據庫之間的確是有防火墻存在。因此我們可以總結出兩點:1,全面的知識對診斷數據庫問題很有幫助。2, 如果經過詳盡分析問題發現與別人說的不一致,需要堅持,并需要為自己的堅持尋找更多的數據來證實。
--The End--
DCD,?network
Address:? http://www.laoxiong.net/firewall-dcd-and-tcp-keep-alive.html
總結
以上是生活随笔為你收集整理的防火墙、DCD与TCP Keep alive的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。