先看一個不設置timeout形成的線上事故。網絡
有一次生產上的一個服務出了點故障,一個本來每5分鐘執行一次的定時任務忽然不執行了。第一反應是任務執行報錯,查看日誌,卻沒有找到任何異常報錯信息。工具
但經過日誌能夠肯定的是,該任務線程還在執行中。按照這個定時任務執行的業務邏輯來講,這是不正常的,除了一個HTTP請求外,其它都是不耗時的操做。那麼問題只多是出在HTTP請求之上了。性能
經過jstack查看線程的堆棧信息,肯定了就是HTTP請求的問題了。spa
從上面的堆棧信息,能夠看到該定時任務線程處於「RUNNABLE」狀態,在JVM中"RUNNABLE"表示線程運行在JVM中,但在等待操做系統的其餘資源。從堆棧信息中看到,該線程正在進行Socket的讀取操做。操作系統
從發現任務執行,到定位到這裏,已通過去十幾分鍾了,Socket一直在讀取等待中,說明沒有設置超時時間,或者說超時時間沒有生效。計算機網絡
回頭看程序代碼,發現這個服務的HTTP工具類沒有設置HTTP timeout。隨後,趕忙設置timeout。線程
一般健壯的程序都是要設置超時時間的,上面的程序沒有設置超時時間,能夠說是一段有缺陷的代碼。但是這樣一段有缺陷的代碼,爲何能在生產環境跑了好久,最後才暴露出問題呢?日誌
我想主要是由於,即便你不設置超時時間,在正常狀況下,一個HTTP請求老是會返回結果,即便可能會耗時較長。對於一個負載不高的服務來講,潛在的問題沒有暴露出來。接口
那麼什麼狀況下,沒有設置超時時間會形成嚴重的影響呢?資源
前面兩種狀況比較好理解,問題是什麼狀況下,HTTP請求會永遠得不到響應呢?
瞭解計算機網絡應該都知道TCP創建鏈接時的三次握手和斷開鏈接時的四次揮手。
TCP在斷開鏈接時,若是出現異常狀況,致使TCP鏈接的一端異常奔潰,好比電源掉電、系統奔潰、網絡故障等。
在這種狀況下,TCP的斷開操做不會通知對端程序,從而致使對端程序一直處於等待狀態,Socket不能及時釋放。這種一端開着,一端已經關閉的狀態,被稱爲半開鏈接。
回顧上面的生產故障,它恰好就是處於「半開鏈接」的狀態,致使任務線程一直在等待響應結果。爲了不這種狀況的發生,超時時間是必需要設置的。