記錄一個HttpClient超時連接配置不生效的問題排查過程

現象

首先有一個被服務由於內存有限,導致巨卡。導致調用他的服務出現線程阻塞。jstack打印線程池如下所示:

開始排查解決問題

第一步:檢查代碼看是否超時設置是否正確,因爲感覺超時設置正確不可能阻塞。

找到注入client的位置:

發現配置沒有任何問題,此時感到了一點點慌張。(內心OS: 難不成HttpClient還有BUG, 講道理這麼成熟的框架不應該啊)

第二步:本着高效的原則,百度一下是否有其他人踩過這樣的坑了。

咦,這不和遇到的一樣嗎? 心想搞定。看我jstack棧阻塞堆棧信息,也是有重試的信息,如下圖所示:

那麼直接更改我們的client注入代碼爲如下:

以爲到這裏故事就結束了,開開心心重新部署一下,就去玩其他的了。

噩夢再次上演:幾天後,被調用服務再次出現卡頓,然後調用方又阻塞了,what fuck !

老規矩看堆棧信息:

還是熟悉的配方,一樣的錯誤,阻塞在同一個地方。本着高效的原則,GPT了一下,然並沒有什麼用,都是一些太泛的思路,這玩意幹精細活還是有缺陷:

那這樣的話,就苦逼了,只能慢慢的擼他源碼了。因爲服務器卡頓是偶現,還沒法調試。找到構建過程如下:

顯然實際執行在InternalHttpClient裏面。點進去看一下他的執行過程:

發現我們配置的requestConfig可能並未生效,他可能直接從Request裏面取,那這顯然有可能在調用方給Request手動配置requestConfig。 找到調用處的代碼:

顯然確實有可能是這個原因,那有了上次的經驗,我們要驗證一下。由於服務器卡頓是偶現,我們debug看一下是不是走到這裏了:

發現都是-1, 那應該就是這個問題了,Request配置,重新打包部署,問題再也沒有復現過。over!

題外話

源碼定位問題的過程省略了很多,所以看起來解決問題過程似乎很簡單。因爲框架代碼畢竟那麼多,我第一步先是猜想要先定位到他超時判斷邏輯的代碼在哪裏,才能知道爲什麼不生效。定位了很久才發現框架本身並無相關邏輯,他是構建了一個Socket去請求,在socket中有兩個時間,一個是soTimeOut(讀流超時時間), 一個是connectTimeOut(連接超時時間)。 其在創建socket的時候需要指定connectTimeOut,然後soTimeOut可在發起請求前設置。 當然這也反應出分析問題不夠冷靜, 忽略了基本的網絡常識,這些成熟的框架,一開始就應該思考是不是配置不正確的問題,究其原因也是對框架不夠深入瞭解,不知道具體的某個請求可能還存在可以配置單獨的RequestConfig對象,一味的關注CloseableHttpClient的配置去了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章