単純なApacheインスタンスから負荷分散環境に移行して以来、POSTリクエストが繰り返されるという問題が発生することがあります。nginxをリバースプロキシとして実行しています。静的コンテンツはnginx自体によって提供されています。動的コンテンツは2つのApacheバックエンドから提供されます。
インターフェース/ユーザーのエラーではないことを確認しました。簡単な例:単純な画像アップロードでは、画像が2回アップロードされます。リクエスト/ POSTは、ダブルクリックまたはユーザーエラーによって2回送信されることはありません。ブラウザーがリクエストを2回送信しているという証拠を見つけられなかったので、私の疑いはサーバー側にあります。 (これは疑いのみであることに注意してください。)これらの要求のほとんどは内部的なものであり、つまり従業員からのものであるため、どのようにして発生するかを確認できます。
私が見つけることができる唯一の「間違った」ことは、nginxが499
これらの場合のエラー。ただし、これが問題の原因なのか、それとも単なる(副次的な)影響なのかはわかりません。 (私は499がデフォルトのhttpステータスではないことを知っています、それは「クライアントが接続を閉じた」ことを意味するnginxステータスです)
繰り返されるPOST要求は、時間がかかる可能性のあるほとんどすべての要求です。ここで例として示しているのは、単純な画像のアップロードですが、スクリプトはバックグラウンドでいくつかの処理を実行します(画像は異なるフォーマット/サイズに変換する必要があり、両方のサーバーに配布する必要があります)。
たとえば、画像のアップロードです。 nginxは1つの「499」と1つの200リクエストをログに記録しますが、Apacheは2つのリクエストを受信(および処理)しています。
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エラーを読み込もうとしました。結論は、「クライアントが接続を閉じた」ということです。それはバックグラウンドのケースかもしれませんが、これがどのようにして2番目のリクエストが発行されるべきであるか、そして「ユーザーがブラウザを閉じた」のようなものが起こっていないことは確かではありません。
現在、より遅いPOSTリクエストを分割するのに役立つようです(複数の処理がある場合は、ユーザーに1を選択させ、POSTもう1つ)、しかし、これはそれが発生する可能性を単に低くしている可能性があります。
これは明らかに一時的な解決策です。それがisタイムアウトの場合、どこを見つけて対応する数値を増やす必要がありますが、なぜタイムアウトがこの動作を引き起こすのかはわかりません。 "メッセージではなく、繰り返し。
POSTが繰り返される原因となるプロセス/状況を特定するために探しています。もちろん、「理由は不明ですが、このタイムアウトを増やすことで修正されます」というのは、上手。
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;
}
geo
の一部だけでなく、SSL
の一部のIP固有の行も削除して、単純にしました。必要に応じてそれらを置き換えることができますが、結局、sslバックエンド用の追加のgeo
部分、および対応するアップストリームと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;
}
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;
}
より長い説明:
私はちょうどあなたが説明した問題にちょうど遭遇したと思います:
499
ステータスを示し、同じリクエストが異なる上流ノードに表示されますこれは実際にはnginxのリバースプロキシとしてのデフォルトの動作であり、それをより高いバージョンにアップグレードしてもこの問題は解決されませんが、可能な解決策として示されています here が、これは別のアドレスです問題。
これは、ロードバランサーとしてのnginxが上流ノードを ラウンドロビン方式 で選択するために発生します。選択したノードが失敗すると、要求は次のノードに送信されます。ここで注意すべき重要な点は、ノード障害はデフォルトで error or timeout
として分類されることです。 proxy_read_timeout
を設定していないため、デフォルトは60秒です。したがって、60秒間待機した後、nginxは次のノードを選択し、同じリクエストを送信します。
したがって、1つの解決策は、このタイムアウトを増やして、長時間実行オペレーションを完了できるようにすることです。 proxy_read_timeout 120;
(またはニーズに合った制限)を設定します。
もう1つのオプションは、proxy_next_upstream error;
を設定して、タイムアウトの場合にリバースプロキシが次のノードを使用しないようにすることです。または、上記のように、これらのオプションを両方とも設定できます。