記一次生產環境Nginx 502 bad gateway問題分析解決過程

問題:膠東移動體驗上線部署後,訪問web通過nginx訪問接口返回502 bad gateway,查看nginx錯誤日誌如下:

2020/04/28 20:24:31 [error] 2056#7704: *430 WSARecv() failed (10054: An existing connection was forcibly closed by the remote host) while reading response header from upstream, client: 10.98.11.10, server: , request: "GET /log-service/log/crash/list?crashStatus=&startTime=1587398400000&endTime=1588089599999&desc=1&page=0&pageSize=10 HTTP/1.0", upstream: "http://10.64.22.21:9999/log-service/log/crash/list?crashStatus=&startTime=1587398400000&endTime=1588089599999&desc=1&page=0&pageSize=10", host: "10.98.11.10:5555", referrer: "http://10.98.11.10/"

根據信息看出問題是,nginx與上游服務器的連接被強行斷開,但爲什麼會被斷開呢?

第一反應就是nginx所在dmz去服務器與應用服務器網不同,但是兩服務器之間的網絡策略都做好了,而且其他接口訪問都是正常的,項目經理那邊反饋的信息是網都配好了,自己ping 和telnet端口都沒問題,便認爲不是網絡的問題(此處買下的此次不太成功解決問題的伏筆)

 

通過在網上搜索資料,大多說的都是關於長連接的配置,配了一通沒有任何效果後,再思考不用長連接可否,於是將nginx keepalive_timeout 設置成 0,再啓動nginx後,發現不止原來的接口仍不好使,現在所有的接口都502了......再看錯誤日誌,現在換成另外一個錯了

2020/04/28 22:27:45 [error] 3004#6500: *211 no live upstreams while connecting to upstream, client: 10.98.11.10, server: , request: "GET /zuul/configure-service/config_dict/item/ARTICLE_UUID HTTP/1.0", upstream: "http://nginx_zuul/zuul/configure-service/config_dict/item/ARTICLE_UUID", host: "10.98.11.10:5555", referrer: "http://10.98.11.10/"

也就是nginx請求時,沒有找到可用的上游服務器,沒啥沒有上游服務器呢,nginx上游服務器兩臺網關服務器,都正常運行,一測都能夠走通,這下更是百思不得其解了

不得已再次配置長連接,配置後大部分接口正常了,崩潰日誌接口仍然502。

爲什麼不配置長連接就是找不到上游服務器呢:

查看網關服務器發現大量的端口處在time_wait狀態,我們只配了前端-->Nginx的長連接,但是nginx-->API的長連接卻沒有配置,默認情況下nginx訪問後端都是用的短連接,當大量訪問產生後,後端服務沒有可用端口和nginx連接通信。此處有疑問這種情況往往出現在壓測的情況下,而此時系統負載並不太大爲啥會出現?

此問題的解決過程,參考下述文章:

https://xiezefan.me/2017/09/27/nginx-502-bug-trace/

https://www.cnblogs.com/zjfjava/p/10909087.html

https://blog.csdn.net/weixin_34220179/article/details/92601408

繼續分析通過nginx訪問崩潰日誌接口502的問題,通過抓包發現:

 

當nginx所在的服務器(10.98.11.5)嚮應用服務器(10.64.22.21)發送崩潰日誌請求時,21返回的數據包,標識TCP復位,顯示21-->5的網絡有問題!

 

關於TCP RST標識:

RST表示復位,用來異常的關閉連接,在TCP的設計中它是不可或缺的。就像上面說的一樣,發送RST包關閉連接時,不必等緩衝區的包都發出去(不像上面的FIN包),直接就丟棄緩存區的包發送RST包。而接收端收到RST包後,也不必發送ACK包來確認。

TCP處理程序會在自己認爲的異常時刻發送RST包。例如,A向B發起連接,但B之上並未監聽相應的端口,這時B操作系統上的TCP處理程序會發RST包。

又比如,AB正常建立連接了,正在通訊時,A向B發送了FIN包要求關連接,B發送ACK後,網斷了,A通過若干原因放棄了這個連接(例如進程重啓)。網通了後,B又開始發數據包,A收到後表示壓力很大,不知道這野連接哪來的,就發了個RST包強制把連接關了,B收到後會出現connect reset by peer錯誤。

 

此次解決問題過程可總結兩點經驗:

1、遇到問題時,先從簡顯處排查,像這次剛開始就是直接測接口抓包,就不用後來死扣長連接不得其解了

2、生產環境涉及多服務間問題的排查時,抓包工具有很大幫助

 

文章最後還有一個疑問:爲什麼其他接口都訪問時,5到2021都沒問題,只有崩潰日誌訪問時纔有問題,尚待繼續研究

 

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