前言:當我們使用Golang構(gòu)造一個Http請求時蛋逾,往往會忽略一些細節(jié),尤其是在高并發(fā)的情況下窗悯,會暴露出一些問題区匣。而且這些問題是很難去排查的,比如我最近遇到的這個BUG蒋院,在大規(guī)模高并發(fā)的生產(chǎn)環(huán)境下亏钩,排查日志會發(fā)現(xiàn)極少數(shù)的請求會失敗莲绰,報錯如下圖所示,這是什么原因呢姑丑?
經(jīng)過排查我發(fā)現(xiàn)蛤签,造成問題的最可能原因是服務(wù)器正在關(guān)閉連接的時候又接收到新的請求,所以這個請求就被服務(wù)器拒絕而失敗栅哀。
要解決這個問題震肮,我們需要了解Golang是如何實現(xiàn)connection的。經(jīng)過翻閱資料我發(fā)現(xiàn)connection包含兩個協(xié)程昌屉,一個用于讀钙蒙,一個用于寫(就是readLoop和writeLoop)。在大多數(shù)情況下间驮,readLoop會檢測socket是否關(guān)閉躬厌,并適時關(guān)閉connection。如果一個新請求在readLoop檢測到關(guān)閉之前就到來了竞帽,那么就會產(chǎn)生EOF錯誤并中斷執(zhí)行扛施,而不是去關(guān)閉前一個請求。
那么要怎么解決這個問題呢屹篓?其實很簡單疙渣,只需要設(shè)置request的Close屬性為true即可,代碼如下:req.Close = true?
它會阻止連接被重用堆巧,可以有效的防止這個問題妄荔,也就是Http的短連接。對于客戶端請求谍肤,設(shè)置此字段可以防止在發(fā)送到相同主機的請求之間重復(fù)使用TCP連接
Golang源碼中對于req.Close的解釋如下圖所示:
Close表示是在回復(fù)此請求(對于服務(wù)器)后還是在發(fā)送此請求并讀取其響應(yīng)(對于客戶端)后關(guān)閉連接啦租。
對于服務(wù)器請求,HTTP服務(wù)器會自動處理荒揣,處理程序不需要此字段篷角。
對于客戶端請求,設(shè)置此字段可以防止在發(fā)送到相同主機的請求之間重復(fù)使用TCP連接系任。
總結(jié):只需要設(shè)置req.Close = true就可以解決這個BUG恳蹲,雖然很簡單,但是它背后所帶來的高并發(fā)問題還是值得我們學習的俩滥,讓我對高并發(fā)有了更深的理解嘉蕾。