有关连接超时那些事
一 JDBC
jdbc是java連接關(guān)系型數(shù)據(jù)庫的標(biāo)準(zhǔn)API,Sun公司一共定義了4種類型的JDBC,我們主要使用的是第4種,該類型的Driver完全由Java代碼實現(xiàn),通過使用socket與數(shù)據(jù)庫進(jìn)行通信。
第4種類型的JDBC底層通過socket對字節(jié)流進(jìn)行操作,因此也會有一些基本網(wǎng)絡(luò)操作,當(dāng)在網(wǎng)絡(luò)操作中遇到問題的時候,將會消耗大量的cpu資源,并且失去響應(yīng)超時。
二 常見Timeout
(WAS/BLOC是具體應(yīng)用名稱,不需要關(guān)心)
DBCP 獲取連接超時
數(shù)據(jù)庫連接池getConnection獲取不到
Statement Timeout
statement timeout用來限制statement的執(zhí)行時長,或者statement timeout可以簡單認(rèn)為一次sql的執(zhí)行時間控制,timeout的值通過調(diào)用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API進(jìn)行設(shè)置。
JDBC的超時處理,在不同的數(shù)據(jù)庫里,處理是不一樣的,在這里只說下mysql的,其它數(shù)據(jù)庫的可以翻看傳送門
處理步驟
調(diào)用connection createStatement 創(chuàng)建 statement
執(zhí)行statement的executeQuery方法
statement通過自己的connect發(fā)送query給mysql
statement新創(chuàng)建一個timeout-execution線程用于進(jìn)行超時處理
給statement的原有connection分配一個超時處理線程(^5.1)
向timeout-execution線程進(jìn)行注冊
達(dá)到超時條件
TimerThread調(diào)用JtdsStatement實例中的TsdCore.cancel()方法
timeout-execution線程創(chuàng)建一個同statement對應(yīng)的(配置相同)connection
使用新創(chuàng)建的connection向超時query發(fā)送cancel query(KILL QUERY “connectionId”)
Transaction Timeout
一次事務(wù)的超時控制,一個事務(wù)由多個statement組成,簡單地說,transaction timeout就是“statement Timeout * N(需要執(zhí)行的statement數(shù)量) + @(垃圾回收等其他時間)”。transaction timeout用來限制執(zhí)行statement的總時長。
JDBC Timeout
TCP/IP結(jié)構(gòu)原因,socket無法探知網(wǎng)絡(luò)中斷,因此應(yīng)用無法主動發(fā)現(xiàn)數(shù)據(jù)庫連接斷開。如果沒有設(shè)置jdbc socketTimeout,應(yīng)用就會一直的等待下去,這種連接被稱為dead connection(壞死連接)。
不推薦使用socket timeout來限制statement的執(zhí)行時長,因此socket timeout的值必須要高于statement timeout,否則,socket timeout將會先生效,這樣statement timeout就變得毫無意義,也無法生效。
下面展示了socket timeout的兩個設(shè)置項,不同的JDBC驅(qū)動其配置方式會有所不同。
socket連接時的timeout:通過Socket.connect(SocketAddress endpoint, int timeout)設(shè)置
socket讀寫時的timeout:通過Socket.setSoTimeout(int timeout)設(shè)置
mysql的socket timeout配置方式
jdbc:mysql://xxx.xx.xxx.xxx:3306/database?connectTimeout=60000&socketTimeout=60000
操作系統(tǒng)的socket timeout配置
操作系統(tǒng)可以通過socket timeout進(jìn)行配置,來檢測壞死socket 連接。Linux一般默認(rèn)2小時。
所以有時候會發(fā)現(xiàn)為什么我們沒有設(shè)置jdbc的socket timeou,當(dāng)出現(xiàn)問題后過了段時間奇跡般的好了,那是因為系統(tǒng)幫我們重連了。
sudo sysctl -a|grep keepal
net.ipv4.tcp_keepalive_time = 7200(s)
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
三 案例
系統(tǒng)上線了一段時間,總是時不時的報出一些慢接口、statement 超時的問題甚至出現(xiàn)數(shù)據(jù)庫連接池獲取不到連接的問題。因為這些問題是偶發(fā)性的,并且隨機(jī)出現(xiàn)在某些一兩臺機(jī)器上(當(dāng)前機(jī)器集群>6)又能很快的自我恢復(fù)所以沒有引起重視。
短時間的連接池不夠用
有一次爆發(fā)獲取不到數(shù)據(jù)連接的問題,當(dāng)時立馬看了看GC,QPS,數(shù)據(jù)庫服務(wù)器RT全部正常,但是網(wǎng)絡(luò)出現(xiàn)ping丟包。
網(wǎng)絡(luò)
數(shù)據(jù)庫平均響應(yīng)時間
翻閱日志發(fā)現(xiàn)在這段時間出現(xiàn)了大量的2s響應(yīng)時間的接口,正是這些接口把數(shù)據(jù)庫連接hang住導(dǎo)致連接池連接耗盡,其他請求獲取不到連接。后來經(jīng)過確認(rèn)的確在這段時間出現(xiàn)了網(wǎng)絡(luò)問題(持續(xù)1分鐘),所以我們認(rèn)為是網(wǎng)絡(luò) 丟包 問題導(dǎo)致接口響應(yīng)慢,占用數(shù)據(jù)庫連接不釋放,進(jìn)而引發(fā)數(shù)據(jù)庫連接池不夠用的問題。
網(wǎng)絡(luò)問題再次爆發(fā),持續(xù)獲取不到數(shù)據(jù)庫連接
時運不濟(jì),我們的系統(tǒng)再次出現(xiàn)了接口超時的問題,而這一次卻是出現(xiàn)了致命的故障,因為請求量太大,所以沒有等系統(tǒng)檢測socket 連接,數(shù)據(jù)庫連接池已經(jīng)被耗盡,在大量的請求下,故障越發(fā)的明顯。
案例總結(jié)
第一個案例,我們可以認(rèn)為是網(wǎng)絡(luò)丟包問題引發(fā)連接被hold(jdbc連接沒有壞死)導(dǎo)致其它請求獲取不到連接。也有可能有部分的壞死連接(日志顯示也有請求超時的異常),在低請求量下,問題被掩蓋住了,等過了1分鐘網(wǎng)絡(luò)恢復(fù),網(wǎng)絡(luò)丟包問題沒有了,對應(yīng)的jdbc連接又能很快的響應(yīng)。而那些壞死的連接在系統(tǒng)檢測到后又進(jìn)行了重連。第二個案例應(yīng)該是第一個案例的放大版,請求量大了。
部分摘自 http://www.importnew.com/2466.html
總結(jié)
- 上一篇: netty学习资料
- 下一篇: (转) 一张图解AlphaGo原理及弱点