「不敢去懷疑程式碼,又不得不懷疑程式碼」記一次網路請求超時分析

2022-06-22 12:00:31
摘要:此次定位,頗為複雜,而且有時讓人沒有思路,因為同一個介面,換一個環境又好使了,又不敢去懷疑程式碼;然而有問題的環境,換一個介面也好使了,又不得不懷疑程式碼

本文分享自華為雲社群《一次網路請求超時分析》,作者:xiewenci 。

問題現象

發起http請求,後端服務介面/v5/iot/11c9c88e6fb26bead43b75514dc380eb/routing-rule/rules?limit=10&marker=ffffffffffffffffffffffff&offset=0,一直等待,一分鐘後返回響應,且中文亂碼顯示

分析過程

1.首先定界,在正常環境和異常環境換一樣的版本程式碼,測試同樣介面,但是正常環境正常,異常環境還是等待1分鐘,所以覺得是環境問題,於是下一步,抓包

2.分別再異常環境和正常環境抓包,具體流資訊見下圖:

異常環境的流資訊

正常環境的流資訊

從圖中看出正常環境是,伺服器端傳送響應完成之後,由使用者端正常返回ACK,然後由使用者端發起FIN斷鏈請求。而異常環境則是伺服器端傳送響應完成之後,使用者端也回了ACK,但是沒有主動發起斷鏈請求,直到超過keep-alive時間之後,由伺服器端發起了斷鏈請求(因為超時主動斷鏈)。現象是使用者端一直在等伺服器端傳送響應(可能沒有傳送完),所以懷疑伺服器端有快取之類,沒有及時將響應流傳送出去,所以繼續檢視程式碼

3.檢視程式碼,在返回使用者端的時候,沒有flush和close操作,程式碼如下

然後以為找到問題原因所在了,就嘗試修改程式碼,如下:

增加了flush操作和close操作(放在了try語快中),最後測試執行,還是跟最初的現象一致,還是會等待1分鐘後才會返回響應。這時就有點納悶了,再重新仔細分析下流,其實從流中可以看出來,伺服器端的響應是立馬返回給了使用者端的,如下圖

既然給了響應,那為什麼使用者端為什麼還要繼續等待呢?這裡有注意到圖中有幾個問號,這其實是中文字元亂碼了,所以這裡又懷疑是不是編碼格式導致使用者端收到的Content-Length長度和收到的響應的長度不一致,也就是使用者端實際收到的響應的長度小於Content-Length的長度,然後一直等待下去,所以繼續修改程式碼

4.修改程式碼,指定編碼格式為UTF-8,程式碼如下:

替換環境版本,測試執行,響應就立馬返回了,果然是這個編碼格式的鍋

原因回顧

1.編碼格式不一致就會導致響應流的實際長度不一致?答案是一定的,編碼格式不一致,實際長度就是會不一致,測試結果如下:

2.為什麼之前的沒有出現過這個問題?是什麼原因導致編碼格式丟失的

檢視後端服務jar包,發現spring版本已經升級到5.2.21.RELEASE,此版本中沒有指定預設編碼格式為UTF-8

所以需要後端服務去指定編碼格式,或者閘道器服務統一處理

總結與思考

此次定位,頗為複雜,而且有時讓人沒有思路,因為同一個介面,換一個環境又好使了,又不敢去懷疑程式碼;然而有問題的環境,換一個介面也好使了,又不得不懷疑程式碼;還有就是在容器中去呼叫介面,也是一樣的問題,所以感覺又跟網路沒啥關係。其實應該靜下心來去思考為什麼使用者端那裡一直等待,沒有主動發起斷鏈,這裡還是說明了對HTTP協定細節,不夠熟練掌握,才導致中間走了一些誤區,需要去鞏固和加深對http協定的理解。

 

點選關注,第一時間瞭解華為雲新鮮技術~