NoHttpResponseException問題分析解決記錄
新項(xiàng)目上線遇到NoHttpResponseException的問題
大概11000筆發(fā)到C系統(tǒng)的交易會(huì)出現(xiàn)15筆會(huì)因這種異常而導(dǎo)致失敗,對(duì)月交易量在近三億的系統(tǒng)來說,按照這樣的比例也會(huì)有4萬多筆的交易失敗,這種嚴(yán)重影響客戶體驗(yàn)的現(xiàn)象堅(jiān)決不能容忍。
按照套路網(wǎng)上搜了下這種出現(xiàn)這種異常的原因以及解決辦法,apache網(wǎng)站的解釋是:
In some circumstances,usually when under heavy load, the web server may be able to receive requests but unable toprocess them. A lack of sufficient resources like worker threads is a good example. This may cause the server to drop the connection tothe client without giving any response. HttpClient throws NoHttpResponseException when it encounters such a condition. In most cases it is safe to retry a method that failed with NoHttpResponseException.
意思就是當(dāng)服務(wù)器端由于負(fù)載過大等情況發(fā)生時(shí),可能會(huì)導(dǎo)致在收到請(qǐng)求后無法處理(比如沒有足夠的線程資源),會(huì)直接丟棄鏈接而不進(jìn)行處理。此時(shí)客戶端就回報(bào)錯(cuò):NoHttpResponseException。 建議出現(xiàn)這種情況時(shí),可以選擇重試。
聯(lián)系了W公司的同事,確認(rèn)他們的C系統(tǒng)的負(fù)載還遠(yuǎn)未達(dá)到過載的程度,而且我們發(fā)到他們B系統(tǒng)的交易從來沒有出現(xiàn)過這種異常,他們也無法解釋這種異常產(chǎn)生的原因。
抓包看下tcp連接交互的情況
兩筆異常交易的共同點(diǎn)就是(以圖二為例)C系統(tǒng)在2891個(gè)包發(fā)來了揮手,然后在2893個(gè)包RST了連接,導(dǎo)致我方系統(tǒng)第2888、2889發(fā)的請(qǐng)求沒有收到響應(yīng)就異常結(jié)束了。
2個(gè)問題(自問自推測(cè))
1. C系統(tǒng)為什么會(huì)發(fā)送結(jié)束連接的FIN揮手包?
注意到圖二在第2882個(gè)包C系統(tǒng)返回前一個(gè)請(qǐng)求的響應(yīng)完成(10:16:25),到第2888個(gè)包(10:16:46)我方發(fā)送下一個(gè)請(qǐng)求,之間有個(gè)21s的空閑間隔,圖一中C系統(tǒng)在發(fā)出FIN揮手包之前也有一個(gè)20s的空閑間隔,會(huì)不會(huì)是C系統(tǒng)的服務(wù)器會(huì)在每個(gè)連接空閑20s后自動(dòng)就會(huì)發(fā)起斷開連接呢?再看下圖三正常結(jié)束交易的tcp流,也是在收到客戶端的確認(rèn)包后有20s的空閑間隔。
基本上可以推斷出C系統(tǒng)的服務(wù)器會(huì)在連接空閑20s后自動(dòng)發(fā)起斷開連接。
2. C系統(tǒng)為什么會(huì)直接發(fā)出第2893個(gè)RST包,而不是發(fā)出正常的Ack確認(rèn)包?
按照?qǐng)D二的tcp流序列,客戶端發(fā)出的第2888個(gè)包在收到服務(wù)端發(fā)送的第2891個(gè)FIN包之前,只個(gè)是在客戶端抓的包,請(qǐng)求的網(wǎng)絡(luò)傳輸時(shí)間。C系統(tǒng)的服務(wù)端發(fā)出的FIN包時(shí)很可能還沒收到我方發(fā)送的第2888個(gè)請(qǐng)求。即服務(wù)端發(fā)送FIN包后,馬上就收到了第2888個(gè)請(qǐng)求包,以及第2892個(gè)[FIN、Ack]包,自身無法判斷是正常結(jié)束,所以就發(fā)出來RST包,關(guān)閉連接。
我方系統(tǒng)是用httpclient4.3的60s的長(zhǎng)連接發(fā)送請(qǐng)求,使用的http1.1協(xié)議連接是默認(rèn)keepalive的,同一個(gè)線程的多個(gè)請(qǐng)求可以復(fù)用同一個(gè)長(zhǎng)連接。正是由于c系統(tǒng)發(fā)出FIN包的時(shí)間,與我方在連接空閑了20s時(shí)仍使用這個(gè)連接發(fā)送數(shù)據(jù)時(shí)之間微妙的時(shí)間差,所以導(dǎo)致出異常的交易都滿足這樣一個(gè)現(xiàn)象:即請(qǐng)求發(fā)出去才幾十毫秒就收到了異常。
解決
基本上明確了異常的原因,那解決辦法是?
1. 協(xié)調(diào)W公司變更配置
前面已經(jīng)說了我方系統(tǒng)發(fā)送到W公司B系統(tǒng)的交易,沒有出現(xiàn)過這種異常,說明B系統(tǒng)的服務(wù)端在我方長(zhǎng)連接存在的60s時(shí)間里沒有主動(dòng)發(fā)起斷開此連接,推測(cè)B系統(tǒng)的連接最大空閑時(shí)間是大于60s。這個(gè)需要抓下與B系統(tǒng)的tcp包就可以分析出B系統(tǒng)有沒有主動(dòng)斷開長(zhǎng)連接,空閑多少秒斷開兩個(gè)信息。那可不可以協(xié)調(diào)W公司,請(qǐng)他們將兩個(gè)系統(tǒng)的連接保持最大空閑時(shí)間設(shè)置為一致呢?這個(gè)只能盡力。
2. 優(yōu)化我方系統(tǒng)
1)http請(qǐng)求使用重發(fā)機(jī)制,捕獲NohttpResponseException的異常,重新發(fā)送請(qǐng)求,重發(fā)3次后還是失敗才停止。由于不知道客戶端捕獲到NohttpResponseException這個(gè)異常后,客戶端是否自動(dòng)關(guān)閉了這個(gè)連接,每次重發(fā)都需要新建連接發(fā)送。新建連接不存在太長(zhǎng)的空閑時(shí)間問題,因此能夠通過重發(fā)解決交易失敗的問題。
2)我方系統(tǒng)主動(dòng)檢查每個(gè)連接的空閑時(shí)間,允許設(shè)置連接的最大空閑時(shí)間M,即客戶端建立的連接空閑M秒后,自動(dòng)發(fā)起斷開連接。只要這個(gè)M時(shí)間小于服務(wù)端的最大空閑時(shí)間,將完全避免服務(wù)端主動(dòng)斷開連接導(dǎo)致的異常。
與同事交流,之前鄙司另一個(gè)系統(tǒng)到微信支付請(qǐng)求也遇到同樣的NohttpResponseException異常,tcp抓包信息如下圖:
第47970個(gè)包是服務(wù)端發(fā)來的FIN包,收到響應(yīng)的ack包立刻就想斷開連接(確認(rèn)是開啟keep-alive的,連接保持),而客戶端又發(fā)送了新的請(qǐng)求包過去,服務(wù)端就發(fā)送了三條RST包,斷開了連接。異常的原因推測(cè)是apache網(wǎng)站的解釋,對(duì)方負(fù)載過大主動(dòng)斷開連接,也按照網(wǎng)站推薦的做法,捕獲異常重發(fā),后面就沒有再遇到因這種異常而引起交易失敗。
以上就是NoHttpResponseException問題分析解決記錄的詳細(xì)內(nèi)容,更多關(guān)于NoHttpResponseException問題解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot如何獲取Get請(qǐng)求參數(shù)詳解
SpringBoot為我們封裝了許多簡(jiǎn)便的獲取請(qǐng)求參數(shù)的方法,下面這篇文章主要給大家介紹了關(guān)于SpringBoot如何獲取Get請(qǐng)求參數(shù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12Java如何實(shí)現(xiàn)http接口參數(shù)和返回值加密
這篇文章主要介紹了Java如何實(shí)現(xiàn)http接口參數(shù)和返回值加密問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Java+Appium實(shí)現(xiàn)屏幕錄制功能
這篇文章主要介紹了Java如何利用Appium實(shí)現(xiàn)屏幕錄制功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06SpringBoot中處理的轉(zhuǎn)發(fā)與重定向方式
這篇文章主要介紹了SpringBoot中處理的轉(zhuǎn)發(fā)與重定向方式,分別就轉(zhuǎn)發(fā)和重定向做了概念解說,結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11詳解spring mvc 請(qǐng)求轉(zhuǎn)發(fā)和重定向
這篇文章主要介紹了詳解spring mvc 請(qǐng)求轉(zhuǎn)發(fā)和重定向,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02idea使用pagehelper實(shí)現(xiàn)后端分頁(yè)功能的步驟詳解
這篇文章主要介紹了idea使用pagehelper實(shí)現(xiàn)后端分頁(yè)功能的步驟,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09