Nginx: recv() failed (104: connection reset by peer) 問題排查

recv() failed (104: connection reset by peer) 問題排查

最近項目中通過Nginx反向代理nodejs(採用nestjs框架)服務,壓測過程中概率性出現502 Bad Gateway,出現概率較低,大概在0.005%左右,查看日誌具體報錯信息爲recv() failed (104: Connection reset by peer) while reading response header from upstream,通過查找資料,瞭解到該報錯的直接原因就是:

nodejs服務已經斷開了連接,但是未通知到Nginx,Nginx還在該連接上收發數據,最終導致了該報錯。

考慮到在Nginx中我們配置了打開與nodejs server的長連接,即:

proxy_http_version 1.1;
proxy_set_header Connection "";

我們先從長連接相關的設置入手查找問題,Nginx常用的幾個影響長連接的參數設置有:keepalive_timeoutkeepalive_requestskeepalive

  • 1)keepalive_timeout: 設置客戶端的長連接超時時間,如果超過這個時間客戶端沒有發起請求,則Nginx服務器會主動關閉長連接,Nginx默認的keepalive_timeout 75s;。有些瀏覽器最多隻保持 60 秒,所以我們一般設置爲 60s。如果設置爲 0,則關閉長連接。

  • 2)keepalive_requests:設置與客戶端的建立的一個長連接可以處理的最大請求次數,如果超過這個值,則Nginx會主動關閉該長連接,默認值爲100

    一般情況下,keepalive_requests 100基本上可以滿足需求,但是在 QPS 較高的情況下,不停的有長連接請求數達到最大請求次數而被關閉,這也就意味着Nginx需要不停的創建新的長連接來處理請求,這樣會可能出現大量的 TIME WAIT

  • 3)keepalive: 設置到 upstream 服務器的空閒 keepalive 連接的最大數量,當空閒的 keepalive 的連接數量超過這個值時,最近使用最少的連接將被關閉,如果這個值設置得太小的話,某個時間段請求數較多,而且請求處理時間不穩定的情況,可能就會出現不停的關閉和創建長連接數。我們一般設置 1024 即可。特殊場景下,可以通過接口的平均響應時間和QPS估算一下。

  • 4)開啓與 upstream 服務器的長連接

    默認nginx訪問後端都是用的短連接(HTTP1.0),每次請求來了就新開一個連接,處理完後就關閉該連接,下一次請求再重新開啓。HTTP協議中從1.1版本之後開始對支持長連接。因此我們會在location中設置以下參數來開啓長連接:

      http {
          server {
              location /  {
                  proxy_http_version 1.1;
                  proxy_set_header Connection "";
              }
          }
      }
    

1)和 2)是設置客戶端和Nginx之間的長連接,3)和 4)是設置 Nginx 和 server 之間的長連接。

以上參數配置都覈對過沒有問題後,我們開始從node中查找是否有與keepalive相關的配置,通過查找nodejs文檔,發現nodejs中默認的server.keepAliveTimeout時間爲 5000ms ,這樣如果在 5000s 的超時界限點,Nginx還未收到 Node 端的關閉通知,還繼續在該長連接上收發數據,那麼就可能出現上述的報錯,

因此我們適當加大 node 端的 keepAliveTimeout 值(參考https://shuheikagawa.com/blog/2019/04/25/keep-alive-timeout/):


// Set up the app...
const server = app.listen(8080);

server.keepAliveTimeout = 61 * 1000;
server.headersTimeout = 65 * 1000; // Node.js >= 10.15.2 需要設置該值大於keepAliveTimeout

延長 node 端的 keepAliveTimeout 值的目的就是爲了防止 Nginx 的在 node 服務之前斷開連接,被調用方的超時時間需要大於調用方。

經過上述修改後,壓測時Nginx未出現過502 Bad Gateway的報錯。

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