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