Apache-2.2

使用 nginx 負載平衡伺服器重複 POST 請求(狀態 499)

  • June 13, 2016

雙重上傳

自從我們從一個簡單的 Apache 實例轉變為負載均衡環境後,有時會出現重複 POST 請求的問題。我們將 nginx 作為反向代理執行。靜態內容由 nginx 本身提供,動態內容由兩個 Apache 後端提供。

我檢查過它不是界面/使用者錯誤。一個小例子:一個簡單的圖像上傳將導致圖像被上傳兩次。請求/POST 不會通過點兩下或使用者失敗發送兩次。我沒有發現任何證據表明瀏覽器發送了兩次請求,所以我懷疑是在伺服器端。(請注意,這只是懷疑。)這些請求大部分是內部的,這意味著它們來自員工,所以我可以驗證它們是如何產生的。

我能找到的唯一“錯誤”是 nginx499在這些情況下會記錄錯誤。但是,我不確定這是問題的原因還是(副作用)。(我知道 499 不是預設的 http 狀態,它是 nginx 狀態,意思是“客戶端已關閉連接”)

要求

重複的 POST 請求幾乎是所有可能需要一段時間的請求。我在這裡展示的一個例子是一個簡單的圖像上傳,但腳本在後台做了一些事情(圖像必須轉換成不同的格式/大小,並且應該分發到兩個伺服器等)。

日誌

一個例子是上傳圖片。nginx 將記錄一個“499”和一個 200 請求,但 Apache 正在接收(並處理!)兩個請求。

阿帕奇

[17:17:37 +0200] "POST ***URL** HTTP/1. 0" 200 9045   
[17:17:47 +0200] "POST ***URL** HTTP/1. 0" 200 20687

nginx

[17:17:47 +0200] "POST ***URL** HTTP/1.1" 499 0 
[17:17:52 +0200] "POST ***URL** HTTP/1.1" 200 5641

懷疑

在我看來,更大/更慢的上傳更受此影響,所以我懷疑超時。我試圖閱讀 499 錯誤:結論似乎是“客戶端關閉連接”。這可能是後台的情況,但我不確定這意味著應該發出第二個請求,並且肯定不會發生“使用者關閉瀏覽器”之類的事情。

目前,它似乎有助於分解較慢的 POST 請求(如果有很多事情要做,只需讓使用者選擇 1 並為另一個選擇第二次 POST),但這可能只是降低了它發生的機會。沒有把握。

這顯然是一個臨時解決方案。如果超時,我需要找出在哪裡並增加相應的數字,但我不確定為什麼超時會導致這種行為:我懷疑是“嗯,出錯了”消息,而不是重複。

問題

我正在尋找哪些過程/情況會導致重複發布 POST。當然,任何“不確定為什麼,但可以通過增加此超時時間來解決”也很好。

nginx 配置

NGINX.conf

user  nginx;
worker_processes  2;
worker_rlimit_nofile 10240;

error_log  /var/log/nginx/error.log error;
pid        /var/run/nginx.pid;


events {
   multi_accept on;
   worker_connections  4096;
   use epoll;
}

http {
   include       /etc/nginx/mime.types;
   default_type  application/octet-stream;

   log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

   access_log  /var/log/nginx/access.log  main;

   sendfile        on;
   tcp_nodelay     off;    
   client_max_body_size    30m;
   keepalive_timeout  65;
   include /etc/nginx/conf.d/*.conf;
}

conf.d

我已經刪除了geo元件中的一些特定於 IP 的行以及SSL變體,以保持簡單。如果需要,我可以替換它們,但歸結geo為 ssl 後端以及相應的上游和 conf 文件的額外部分。

geo $backend {
   default apache-backend;
}

upstream apache-backend {
   ip_hash;
   server SERVER1 max_fails=3 fail_timeout=30s weight=2;
   server SERVER2 max_fails=3 fail_timeout=30s weight=3;
}

conf.d/somestring.conf

limit_conn_zone $binary_remote_addr zone=somestring:10m;
server {
   listen ip1:80;
   listen ip2:80;
   server_name name.tld www.name.tld;

   root PATH

   access_log PATH/name.log main;

   location / {
           proxy_pass              http://$backend;
   }

           //*some more locations**//

   gzip on;
   gzip_http_version 1.0;
   gzip_comp_level 2;
   gzip_proxied any;
   gzip_min_length 1100;
   gzip_buffers 16 8k;
   gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
}

conf.d/proxy.conf

proxy_set_header        Accept-Encoding "";
proxy_set_header        X-Real-IP $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        Host $http_host;

proxy_buffering         on;
proxy_read_timeout      90;
proxy_buffer_size       32k;
proxy_buffers           8 32k;
proxy_busy_buffers_size    32k;
proxy_temp_file_write_size 32k;

這個論壇主題中,我們了解到罪魁禍首可能是 SPDY。對於那個使用者來說,禁用它似乎是一個解決方案,而且自從禁用它以來,我們也沒有發布過雙重文章。

確切的問題,除了“SPDY 做到了”,目前尚不清楚,建議的解決方案(禁用 SPDY)的副作用顯然是“不再有 SPDY”,但我們可以忍受。

在錯誤再次出現之前,我將其稱為“修復”(或至少:問題的解決方案)。

編輯:我們還沒有(25-02-2014)看到這個問題出現了,所以這確實是一個持久的解決方案。

簡短的回答:試試這個你的位置塊:

location / {
 proxy_read_timeout 120;
 proxy_next_upstream error;
 proxy_pass http://$backend;
}

更長的解釋:

我想我剛剛遇到了你描述的問題:

  • 我使用 nginx 反向代理作為負載均衡器
  • 對於長時間執行的請求,後端會多次收到相同的請求
  • 上游節點的 nginx 訪問日誌顯示499這些請求的狀態,並且相同的請求出現在不同的上游節點

事實證明,這實際上是 nginx 作為反向代理的預設行為,因此將其升級到更高版本將無法解決此問題,儘管此處給出了可能的解決方案,但這解決了另一個問題。

發生這種情況是因為 nginx 作為負載均衡器以循環方式選擇上游節點。當選擇的節點失敗時,請求被發送到下一個節點。這裡要注意的重要一點是節點故障預設歸類為error or timeout. 由於您沒有設置 a proxy_read_timeout,因此預設值為 60 秒。所以在等待 60 秒後,nginx 會選擇下一個節點並發送相同的請求。

因此,一種解決方案是增加此超時,以便您可以完成長時間執行的操作,例如通過設置proxy_read_timeout 120;(或任何適合您需要的限制)。

另一種選擇是阻止反向代理嘗試使用下一個節點,以防超時,通過設置proxy_next_upstream error;. 或者,您可以按照上面的建議設置這兩個選項。

引用自:https://serverfault.com/questions/523340