Die Übertragung großer temporärer Dateien bleibt im Nginx-PHP-FPM-Proxy hängen

Die Übertragung großer temporärer Dateien bleibt im Nginx-PHP-FPM-Proxy hängen

Wir haben einen Server, auf dem eine WordPress-Site mit einem von Serverpilot installierten Nginx-Stack auf Ubuntu 20 LTS läuft.

Sehr große Uploads scheinen bei der Übergabe zwischen dem Nginx-Proxy und PHP hängen zu bleiben, und ich bin am Ende meiner Möglichkeiten angelangt, Probleme zu beheben, ohne einfach herumzustochern und zu sehen, was passiert (was selten eine gute Zeitnutzung oder ein guter Weg ist, um voranzukommen). Soweit ich das beurteilen kann, habe ich die erforderlichen Timeouts erhöht und alle Festplattenlimits angehoben, aber offensichtlich fehlt mir immer noch etwas.

Für unseren Anwendungsfall müssen wir Uploads von bis zu 50 GB zulassen, was in einer Staging-Umgebung, in der ein Standard-LAMP-Stack ausgeführt wird, problemlos funktioniert. Mit Dateien unter ~2 GB haben wir keine Probleme, aber alles darüber kann aufgrund einiger Kriterien, die ich nicht ermitteln konnte, fehlschlagen oder auch nicht. Bei der früheren Fehlerbehebung des Problems schien der Zeitpunkt, zu dem das Kopieren der Datei gestoppt wurde, willkürlich (mit Erfolg bis zu 10 GB), aber mit der aktuellen Konfiguration (siehe unten) wird es konsequent gestoppt, wenn die PHP- tmpDatei 2 GB erreicht.

Wenn wir sehr große Dateien hochladen, können wir beobachten, wie die eingehende temporäre Datei Speicherplatz verbraucht, bis die gesamte Datei vorhanden ist /mnt/tmp/[nginx_tmp_path](ja, es ist genügend Speicherplatz verfügbar). Danach können wir sehen, wie die Datei in den PHP- tmpPfad kopiert wird, aber nach einigen Sekunden tmpwächst die PHP-Datei nicht mehr weiter und der Kopiervorgang bleibt hängen. Schließlich wird eines der 600-Sekunden-Timeouts erreicht und es werden Fehler protokolliert (siehe unten). In diesem Screenshot haben wir einen abgeschlossenen (aus der Sicht des Browsers/Endbenutzers) Upload von 14,8 GB, der bei der temporären Dateiübertragung bei etwa 2 GB hängen blieb. PHP tmp-Datei wächst nicht mehr

Am Ende des 600-Sekunden-Zeitraums steht Folgendes im Apache-Fehlerprotokoll:

(70008)Partial results are valid but processing is incomplete: [client <MY_IP>] AH01075: Error dispatching request to : (reading input brigade), referer: https://<THE_URL>/wp-admin/media-new.php

Und das Nginx-Fehlerprotokoll sagte Folgendes:

2512066#0: *9 upstream timed out (110: Connection timed out) while sending request to upstream, client: <MY_IP>, server: <INTERNAL_IP>, request: "POST /wp-admin/async-upload.php HTTP/2.0", upstream: "http://127.0.0.1:81/wp-admin/async-upload.php", host: "<THE_URL>", referrer: "https://<THE_URL>/wp-admin/media-new.php"

Es ist wichtig zu beachten, dass diese Meldungen erst 10 Minuten nach dem vollständigen Eintreffen des Uploads auf dem Server in der Protokolldatei erscheinen, also 9 oder mehr Minuten, nachdem das Kopieren der Datei scheinbar angehalten/hängengeblieben ist. Ich bin davon überzeugt, dass etwas die Ursache dafür ist, dass das Kopieren der Datei hängen bleibt und dann irgendwann ein Timeout erreicht wird – ich glaube nicht, dass das Problem am Timeout selbst liegt. In der Zwischenzeit zwischen dem Anhalten des Kopierens der Datei und dem Erscheinen des Timeout-Fehlers in der Protokolldatei gibt es keine erhöhte oder ungewöhnliche Aktivität auf dem Server und alle Dienste funktionieren und reagieren wie erwartet.

Mit der aktuellen Konfiguration tmpwächst die PHP-Datei immer auf 2097152 KB (laut du -a), was mich glauben lässt, dass ich an eine integrierte Dateigrößenbeschränkung stoße, die ich bisher noch nicht entdeckt habe.

Die relevanten Konfigurationsoptionen des Nginx-Servers sind: Im serverKontext:

    proxy_connect_timeout 600;
    proxy_read_timeout 600;
    proxy_send_timeout 600;
    proxy_max_temp_file_size 51200m;

    fastcgi_connect_timeout 600;
    fastcgi_read_timeout 600;
    fastcgi_send_timeout 600;
    fastcgi_request_buffering off;

    keepalive_timeout 600;
    send_timeout 600;

    client_max_body_size 0;
    client_body_temp_path /mnt/tmp;
    client_body_in_file_only clean;

Apaches VirtualHost-Konfiguration:

    RequestReadTimeout header=0 body=0
    Timeout 3600
    ProxyTimeout 3600

Und schließlich die PHP-Konfiguration:

memory_limit = -1
max_execution_time = 0
max_input_time = -1
post_max_size = 50G
upload_max_filesize = 50G
default_socket_timeout = -1

Ich weiß nicht, was die Ursache für das Symptom sein könnte, das ich sehe. Ich bin für jeden Hinweis dankbar!

Zusätzliche Hinweise: Die Symptome geben mir das Gefühl, dass es nicht relevant ist, aber falls doch … Die Site läuft über WP Rocket, aber es gibt keinen externen Proxy-Dienst wie CloudFlare.

AKTUALISIEREN: Ich habe der Nginx-Konfiguration diese Zeilen hinzugefügt:

    proxy_http_version 1.1;
    proxy_set_header Connection "";

Dies hat das Symptom leicht verändert, das Problem aber nicht behoben. Mit dieser Änderung ist das Verhalten wieder so, wie ich es zuvor erklärt habe, und die Dateiübertragung bleibt an einer unvorhersehbaren Stelle stehen. Das erste Beispiel unten stoppte bei 3823176 KB und das zweite bei 3264364 KB. Der Grund für den Unterschied im Verhalten ist mir schleierhaft, aber er ist eine Meldung wert. Bildbeschreibung hier eingeben Bildbeschreibung hier eingeben

AKTUALISIERUNG 2: Ich konnte dies definitiv auf ein Problem bei der Übergabe der tmpDatei zwischen Nginx und PHP zurückführen, kann aber nicht genau sagen, warum der Prozess hängen bleibt.

Wir können den Nginx-Proxy überspringen und nur PHP verwenden, tmpindem wir der Nginx-Konfiguration diese Zeilen hinzufügen:

    proxy_buffering off;
    proxy_request_buffering off;

Bei dieser Konfiguration werden die Dateien direkt in das Verzeichnis übertragen, /mnt/tmp/php<RND_STR>und wenn der Upload abgeschlossen ist, wählt unsere Anwendung die Datei ordnungsgemäß aus tmpund führt ihre Aufgaben aus.

Allerdings verlangsamt dies die Uploads auf etwa 1/3 der verfügbaren Bandbreite und stellt daher keine gute Lösung dar. Es beweist jedoch, dass es sich hier nicht um ein Anwendungsproblem handelt.

Folgendes passiert also:

  1. Der Benutzer lädt eine große Datei hoch (50 GB ist das Maximum in unserem Anwendungsfall)
  2. tmpDie Datei kommt vollständig am Nginx- Speicherort an
  3. Es wird versucht, die Datei von nginx tmpnach PHP zu kopieren tmp. Der Kopiervorgang bleibt nach ein paar Sekunden an einer unvorhersehbaren Stelle, jedoch bei 3 bis 10 GB, stehen. [3b] Jetzt können wir beide tmpDateien sehen und die PHP- tmpDatei enthält eine Anzahl von Bytes, die anwachsen sollte, bis sie der Größe der nginx- tmpDatei entspricht, was aber nicht der Fall ist. Beide Dateien bleiben vollständig unverändert, bis eines der 600-Sekunden-Timeouts erreicht wird (siehe oben). Dann erscheint ein Fehler in den Protokolldateien und beide tmpDateien verschwinden. [3c] Wenn die Datei kleiner als 3 GB ist, wird es jedes Mal funktionieren. Wenn die Datei größer als 3 GB ist, wird es manchmal funktionieren, aber manchmal nicht. Je kleiner die Datei, desto wahrscheinlicher ist es, dass es funktioniert.
  4. Das Umgehen von Nginx tmpfunktioniert vollständig wie erwartet, außer dass die Uploads langsam sind.

Bei der Dateiübergabe zwischen Nginx und PHP bleibt definitiv etwas hängen, tmpwenn die Dateien unverschämt groß sind, und ich würde gerne herausfinden, woran es liegt.

verwandte Informationen