Puncte:0

Transferul de fișiere tmp mare se blochează în proxy nginx php-fpm

drapel cn

Avem un server care rulează un site WordPress cu o stivă nginx instalată de serverpilot pe Ubuntu 20 LTS.

Încărcările foarte mari par să rămână blocate în transferul dintre proxy-ul nginx și PHP și am ajuns la sfârșitul a ceea ce știu cum să depanez fără doar să mă uit la el pentru a vedea ce se întâmplă (ceea ce rareori este o utilizare bună a timpului sau cale de a merge înainte). Din câte îmi pot da seama, am mărit timeout-urile necesare și am ridicat toate limitele de disc, dar evident că încă îmi lipsește ceva.

Pentru cazul nostru de utilizare, trebuie să permitem încărcări de până la 50 GB, pe care le-am funcționat fără probleme într-un mediu de pregătire care rulează o stivă LAMP standard. Nu avem probleme cu fișierele sub ~ 2 GB, dar orice lucru peste acesta poate sau nu eșua pe baza unor criterii pe care nu le-am putut găsi. În timp ce depanați problema mai devreme, ora la care copierea fișierului s-a oprit părea arbitrară (cu succes de până la 10 GB), dar cu configurația actuală (a se vedea mai jos), se oprește constant când PHP tmp fișierul ajunge la 2 GB.

Când încărcăm fișiere foarte mari, putem urmări că fișierul temporar primit consumă spațiu pe disc până când întregul fișier există în /mnt/tmp/[nginx_tmp_path] (da, există o mulțime de spațiu disponibil pe disc). După aceea, putem vedea că fișierul este copiat în php tmp calea, dar după câteva secunde, php tmp fișierul încetează să crească în dimensiune și procesul de copiere se blochează. În cele din urmă, este atins unul dintre intervalele de timp de 600 de secunde și există erori înregistrate (vezi mai jos). În această captură de ecran, avem o încărcare finalizată (din perspectiva browserului/utilizatorului final) de 14,8 GB, care s-a blocat pe transferul de fișiere tmp la aproximativ 2 GB. Fișierul PHP tmp nu mai crește

La sfârșitul perioadei de 600 de secunde, aceasta se află în jurnalul de erori Apache:

(70008)Rezultatele parțiale sunt valide, dar procesarea este incompletă: [client <MY_IP>] AH01075: Eroare la expedierea cererii către : (citirea brigadei de intrare), referer: https://<THE_URL>/wp-admin/media-new.php

Și jurnalul de erori nginx spunea asta:

2512066#0: *9 expirat în amonte (110: conexiune a expirat) în timpul trimiterii cererii către amonte, client: <IP_MEU>, server: <IP_INTERN>, cerere: „POST /wp-admin/async-upload.php HTTP/ 2.0”, în amonte: „http://127.0.0.1:81/wp-admin/async-upload.php”, gazdă: „<THE_URL>”, referitor: „https://<THE_URL>/wp-admin/ media-new.php"

Este important de reținut că aceste mesaje nu apar în fișierul jurnal decât după 10 minute după ce încărcarea ajunge inițial complet la server, adică la 9 sau mai multe minute după ce copia fișierului pare a fi întreruptă/blocată. Sunt convins că ceva face ca copia fișierului să se blocheze și, în cele din urmă, se ajunge la un timeout - nu cred că problema este cu timeout-ul în sine. În intervalul dintre oprirea copierii fișierului și eroarea de timeout care apare în fișierul jurnal, nu există activitate crescută sau neobișnuită pe server și toate serviciile funcționează și răspund conform așteptărilor.

Cu configurația actuală, PHP tmp fișierul crește întotdeauna la 2097152 KB (conform du -a), ceea ce mă face să cred că ating o limită de dimensiune a fișierului încorporată pe care nu am descoperit-o încă.

Opțiunile relevante de configurare a serverului nginx sunt: În Server context:

    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 dezactivat;

    keepalive_timeout 600;
    send_timeout 600;

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

Configurația VirtualHost a Apache:

    RequestReadTimeout header=0 body=0
    Timeout 3600
    ProxyTimeout 3600

Și în sfârșit, configurația PHP:

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

Nu știu ce ar putea cauza simptomul pe care îl văd.Orice indicații sunt apreciate!

Note suplimentare: Simptomele mă fac să simt că nu este relevant, dar în cazul în care este... Site-ul rulează prin WP Rocket, dar nu există un serviciu proxy extern precum CloudFlare.

ACTUALIZAȚI: Am adăugat aceste linii la configurația nginx:

    proxy_http_versiunea 1.1;
    proxy_set_header Conexiune „”;

Acest lucru a schimbat ușor simptomul, dar nu a rezolvat problema. Odată cu această schimbare, comportamentul a revenit la ceea ce am explicat anterior și transferul fișierelor se blochează într-un loc imprevizibil. Primul exemplu de mai jos s-a oprit la 3823176 KB, iar al doilea s-a oprit la 3264364 KB. Motivul diferenței de comportament nu are sens pentru mine, dar merită raportat. introduceți descrierea imaginii aici introduceți descrierea imaginii aici

UPDATE 2: Am reușit să stabilesc definitiv acest lucru pentru a fi o problemă în transmiterea tmp fișier între nginx și php, dar nu reușesc să rezolv exact lucrul care provoacă blocarea procesului.

Putem sări peste proxy-ul nginx și să folosim numai PHP tmp prin adăugarea acestor linii la configurația nginx:

    proxy_buffering dezactivat;
    proxy_request_buffering dezactivat;

Cu această configurație, fișierele intră direct în /mnt/tmp/php<RND_STR> iar când încărcarea este completă, aplicația noastră alege corect fișierul tmp și își îndeplinește sarcinile.

Cu toate acestea, acest lucru încetinește încărcările la aproximativ 1/3 din lățimea de bandă disponibilă, deci nu este o soluție bună. Totuși, demonstrează că aceasta nu este o problemă de aplicație.

Deci iată ce se întâmplă:

  1. Utilizatorul încarcă un fișier mare (50 GB este cazul nostru maxim)
  2. Fișierul ajunge în nginx tmp locația în întregime
  3. Se încearcă copiarea fișierului din nginx tmp în PHP tmp - procesul de copiere se va bloca în câteva secunde undeva imprevizibil, dar între 3 GB și 10 GB. [3b] În acest moment, le putem vedea pe amândouă tmp fișiere și PHP tmp fișierul conține un număr de octeți care ar trebui să crească până când este egal cu dimensiunea nginx tmp dosar, dar nu sunt.Ambele fișiere vor rămâne complet așa cum sunt până când se atinge unul dintre intervalele de timp de 600 de secunde (vezi mai sus), apoi apare o eroare în fișierele jurnal și ambele tmp fișierele dispar. [3c] Dacă fișierul este sub 3 GB, va funcționa de fiecare dată. Dacă fișierul are mai mult de 3 GB, va funcționa uneori, dar nu și altele - cu cât fișierul este mai mic, cu atât este mai probabil să funcționeze.
  4. Ocolind Nginx's tmp funcționează conform așteptărilor, cu excepția faptului că încărcările sunt lente.

Cu siguranță ceva se blochează în timpul tmp transfer de fișiere între nginx și PHP atunci când fișierele sunt îngrozitor de mari și mi-ar plăcea să îmi dau seama ce este.

Michael Hampton avatar
drapel cz
Merită să ne întrebăm de ce aplicația PHP durează mai mult de 600 de secunde pentru a procesa fișierul.
Chris Ostmo avatar
drapel cn
Am mărit toate intervalele de timp, deoarece mă aștept ca transferul unui fișier de 50 GB să dureze mai mult decât 60 de secunde implicite. Nu procesarea PHP va expira - transferul fișierului temporar va expira proxy-ul. Desigur, m-am deschis prea larg în căutarea unei soluții.
Chris Ostmo avatar
drapel cn
... Cu toate acestea, PHP nu durează 600 de secunde pentru a procesa fișierul - ceva se blochează câteva secunde în copierea fișierului, iar 600 de secunde este pur și simplu când nu mai așteaptă și aruncă o eroare. Aplicația noastră PHP nu are șansa de a începe să lucreze la fișier până când nu este mutat din `tmp`, care nu este o stare la care ajungem. (Ne pare rău, am încercat să editez comentariul meu original, dar a fost prea târziu)
Michael Hampton avatar
drapel cz
Hmm. Ei bine, tot ce pot spune cu adevărat din erorile postate este că nginx pare să fi transmis cu succes la Apache, iar Apache nu a reușit să-l transmită către PHP. Pentru mine, acest lucru îl face pe primul suspect codul PHP care se ocupă de încărcare. Ar trebui să implicați dezvoltatorul aplicației. Dar unele alte lucruri par puțin ciudate. Ați montat sisteme de fișiere separate pentru fișierele temporare? Ce tip de sistem de fișiere sunt?
Chris Ostmo avatar
drapel cn
Eu sunt dezvoltatorul și această eroare se întâmplă dintr-un dialog de încărcare media WordPress vanilie, așa că nu există niciun cod în joc aici care să nu fie folosit de o mulțime de oameni. Fișierul nu termină niciodată complet transferul de la tmp-ul lui nginx la tmp-ul PHP, așa că nu cred că aplicația poate interfera. Da, folderul `tmp` este montat pe propria sa partiție ext4. De asemenea, comportamentul în schimbare atunci când schimb configurația serverului nu este în concordanță cu eroarea aplicației.

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.