update 2014-5-18:
今天又處理了一個httpclient阻塞的問題,還是socket read沒有逾時設定。
用jstack -l pid 得到線程的調用棧,每隔一段時間執行一次,對比三次的thread dump結果,發現有一個線程是三次執行的位置一樣的,說明它是阻塞在這裡了:
業務的邏輯是接收一個jms消息,再http請求調用得到處理結果。在http請求處阻塞了,導緻後面的消息都不能消息。
----------------------------------------------
現在的對外接口一般都是http + json的,因為簡單,語言無關。
apache httpclient應該是最常用的java http元件了。這貨有個坑爹的地方,apache httpclient如果對方不回應,或者網絡原因不傳回了,那麼httpclient會一直阻塞。這種情況在公網可能比較容易碰到。在内網時,也有一次因為一台中轉的nginx挂掉而導緻hessian請求長時間阻塞。
因為http client預設的so_timeout是0,即一直等待。
這個問題,在幫同僚查找問題時碰到好幾次了,可能是大家潛意識裡認為http請求是即時的,失敗的話也很快傳回。
apache httpclient的示例也沒提到要設定timeout,這也是比較坑爹的地方。一個庫如果沒有預設阻止使用者去範錯誤,那麼你也應當在文檔,示例代碼裡提醒使用者不要範錯誤。
有三個可以設定time out 的參數:
so_linger最好不要設定,可能會坑死人。參考:
http://unliminet.blog.51cto.com/380895/346686
http://stackoverflow.com/questions/3757289/tcp-option-so-linger-zero-when-its-required