Die POST-Anforderung wird mit dem nginx-Server mit Lastenausgleich wiederholt (Status 499).


8

doppelte Uploads

Seit wir von einer einfachen Apache-Instanz zu einer Umgebung mit Lastenausgleich gewechselt sind, treten manchmal Probleme mit wiederholten POST-Anforderungen auf. Wir führen Nginx als Reverse Proxy aus. Statischer Inhalt wird von Nginx selbst bereitgestellt, und dynamischer Inhalt wird von zwei Apache-Backends bereitgestellt.

Ich habe überprüft, dass es sich nicht um einen Schnittstellen- / Benutzerfehler handelt. Ein kleines Beispiel: Ein einfacher Bild-Upload führt dazu, dass das Bild zweimal hochgeladen wird. Die Anfrage / der POST wird nicht zweimal durch Doppelklick oder Benutzerfehler gesendet. Ich habe keine Beweise dafür gefunden, dass der Browser die Anfrage zweimal sendet, daher liegt mein Verdacht auf der Serverseite. (Beachten Sie, dass dies nur ein Verdacht ist.) Die meisten dieser Anfragen sind intern, dh sie stammen von Mitarbeitern, sodass ich überprüfen kann, wie sie zustande kommen.

Das einzige, was ich falsch finden kann, ist, dass nginx 499in diesen Fällen einen Fehler protokolliert . Ich bin mir jedoch nicht sicher, ob dies die Ursache oder nur eine (Neben-) Wirkung des Problems ist. (Mir ist bekannt, dass 499 kein Standard-http-Status ist, sondern ein Nginx-Status, der bedeutet, dass der Client die Verbindung geschlossen hat.)

Anfragen

Die wiederholten POST-Anfragen sind fast alle Anfragen, die eine Weile dauern können. Das hier als Beispiel gezeigte Beispiel ist ein einfacher Bild-Upload, aber das Skript führt einige Aufgaben im Hintergrund aus (das Bild muss in verschiedene Formate / Größen konvertiert werden und sollte auf beide Server usw. verteilt werden).

Protokolle

Ein Beispiel ist das Hochladen eines Bildes. nginx protokolliert eine '499' und eine 200 Anfrage, aber Apache empfängt (und bearbeitet!) zwei Anfragen.

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

Verdacht

Es scheint mir, dass größere / langsamere Uploads mehr darunter leiden, daher vermute ich eine Zeitüberschreitung. Ich habe versucht, den 499-Fehler nachzulesen: Schlussfolgerungen scheinen zu sein, dass es sich um eine "geschlossene Client-Verbindung" handelt. Das könnte im Hintergrund der Fall sein, aber ich bin mir nicht sicher, wie dies bedeuten würde, dass eine zweite Anfrage ausgegeben werden sollte, und es gibt sicherlich nicht so etwas wie "Benutzer geschlossener Browser".

Derzeit scheint es hilfreich zu sein, langsamere POST-Anforderungen aufzubrechen (wenn mehrere Dinge zu tun sind, lassen Sie den Benutzer einfach 1 und POST ein zweites Mal für das andere auswählen), aber dies könnte nur die Wahrscheinlichkeit verringern, dass sie auftreten. Nicht sicher.

Dies ist offensichtlich eine vorübergehende Lösung. Wenn es sich um eine Zeitüberschreitung handelt, muss ich herausfinden, wo und die entsprechenden Zahlen erhöhen, aber ich bin mir nicht sicher, warum eine Zeitüberschreitung dieses Verhalten verursachen würde: Ich würde eine Meldung "Nun, das ist schief gelaufen" vermuten, keine Wiederholung.

Fragen

Ich möchte herausfinden, durch welchen Prozess / welche Situation ein POST wiederholt werden kann. Natürlich ist auch jedes "nicht sicher warum, aber es wird durch Erhöhen dieser Zeitüberschreitung behoben" großartig.

Nginx-Konfigurationen

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

Ich habe einige IP-spezifische Zeilen in den geoTeilen sowie die SSLVariationen entfernt, um es einfach zu halten. Bei Bedarf kann ich sie ersetzen, aber es geoläuft auf einen zusätzlichen Teil für die SSL-Backends und die entsprechenden Upstreams und Conf-Dateien hinaus.

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;

Und was verwenden Sie für einen Load Balancer?
Michael Hampton

Der Nginx-Reverse-Proxy ist unser Loadbalancer. Ich habe versucht, dies klarer zu machen, indem ich den Loadbalancer in diesem zweiten Satz durch 'Reverse-Proxy' ersetzt habe :)
Nanne,

OK, wie ist Ihre Nginx-Konfiguration?
Michael Hampton

Ich habe es nicht aufgenommen, da ich nicht sicher bin, was die Ursache für die wiederholte Anfrage sein könnte. Wenn Sie vermuten, dass eine bestimmte Einstellung dies nginxkann, würde ich gerne Ihre Gedanken hören. Ich werde die Nginx-Einstellungen gleich veröffentlichen! (Ich wollte dies nicht zu einer Frage machen, bei der "Hier ist der Speicherauszug aller zufälligen Einstellungen, die ich finden konnte", und wie ich hoffentlich erklärt habe, versuche ich herauszufinden, welcher Teil der Kette verantwortlich sein kann)
Nanne

(Wenn es eine Weile dauert, entferne ich alle Dinge wie IPs und andere URL-bezogene Sachen)
Nanne

Antworten:


4

Kurze Antwort: Versuchen Sie dies für Ihren Standortblock:

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

Längere Erklärung:

Ich glaube, ich bin gerade auf genau das Problem gestoßen, das Sie beschrieben haben:

  • Ich benutze Nginx Reverse Proxy als Load Balancer
  • Bei lang laufenden Anforderungen erhält das Backend dieselbe Anforderung mehrmals
  • Die Nginx-Zugriffsprotokolle der Upstream-Knoten zeigen den 499Status für diese Anforderungen an, und dieselbe Anforderung wird in verschiedenen Upstream-Knoten angezeigt

Es stellt sich heraus , dass dies für nginx als Reverse - Proxy tatsächlich Standardverhalten ist, und es auf höhere Versionen eines Upgrade wird daher nicht dieses Problem beheben, obwohl es als eine mögliche Lösung gegeben wurde hier , aber diese Adressen eine andere Frage.

Dies liegt daran, dass nginx als Load Balancer einen Upstream-Knoten im Round-Robin- Verfahren auswählt . Wenn der ausgewählte Knoten ausfällt, wird die Anforderung an den nächsten Knoten gesendet. Hierbei ist zu beachten, dass Knotenfehler standardmäßig als klassifiziert werden error or timeout. Da Sie a nicht festgelegt haben proxy_read_timeout, beträgt der Standardwert 60 Sekunden. Nach 60 Sekunden Wartezeit wählt nginx den nächsten Knoten aus und sendet dieselbe Anfrage.

Eine Lösung besteht darin, dieses Zeitlimit zu erhöhen, damit Ihr langjähriger Vorgang abgeschlossen werden kann, z. B. durch Festlegen proxy_read_timeout 120;(oder eines beliebigen Grenzwerts, der Ihren Anforderungen entspricht).

Eine andere Möglichkeit besteht darin, den Reverse-Proxy daran zu hindern, im Falle einer Zeitüberschreitung zu versuchen, den nächsten Knoten durch Setzen zu verwenden proxy_next_upstream error;. Oder Sie können beide Optionen wie oben vorgeschlagen einstellen.


Hmm, interessant! An Ihrer Antwort scheint nichts falsch zu sein, aber in meinem speziellen Fall bin ich beunruhigt darüber, dass das Deaktivieren von SPDY das Problem behoben hat. Wir haben eine gute Anzahl von Prozessen mit langer Laufzeit, die dieses Verhalten (nicht mehr) zeigen. Vielleicht hat das Deaktivieren von SPDY eine Art sekundäres Verhalten entfernt, das dies zufällig für uns behoben hat, und diese Methode könnte sogar besser sein? Wir haben dieses Problem schon lange nicht mehr gehabt. Ich werde sehen, wie unsere aktuellen Einstellungen sind, und wenn wir diesen Tipp irgendwo einbauen können, danke!
Nanne

Ich habe auch 499's und 502's einmal gesehen, es stellte sich heraus, dass es "nur Zufall" war, obwohl hier zu sehen ist: stackoverflow.com/a/58924751/32453 (als Hinweis, NGINX soll POSTs standardmäßig nicht an den nächsten Server senden, FWIW ...)
Rogerdpack

1

Aus diesem Forenthema haben wir erfahren, dass der Schuldige SPDY sein könnte. Für diesen Benutzer scheint es eine Lösung zu sein, es zu deaktivieren, und wir haben seit dem Deaktivieren auch keine doppelten Beiträge mehr.

Das genaue Problem, außer "SPDY hat es geschafft", ist derzeit nicht bekannt. Die Nebenwirkungen der vorgeschlagenen Lösung (SPDY deaktivieren) sind offensichtlich "kein SPDY mehr", aber wir können damit leben.

Bis der Fehler wieder auftaucht, nenne ich dies eine "Lösung" (oder zumindest: eine Lösung für das Problem).

edit: Wir haben dieses Problem (25-02-2014) nicht mehr gesehen, daher scheint dies in der Tat eine dauerhafte Lösung zu sein.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.