Un client urca fișiere prin formular pe un server cu PHP 8.2, nginx 1.24 și PHP-FPM pe socket Unix. Fișierele mici mergeau, cele peste 8 MB dădeau 502 după exact 60 de secunde. Nu era load, era un singur utilizator. Am păstrat logurile de acces și am cronometrat: cererea ajungea în nginx, trecea la FPM, apoi nimic până la timeout.
Am început cu ce se vede, nu cu presupuneri:
php -i | grep -E 'upload_max_filesize|post_max_size|max_execution_time|max_input_time'
nginx -T | grep -E 'client_max_body_size|fastcgi_read_timeout|proxy_read_timeout'
Valorile erau amestecate: upload_max_filesize=2M, post_max_size=8M, client_max_body_size implicit 1M în nginx, iar fastcgi_read_timeout tot 60s. Am pus limite coerente și am adăugat un buffer explicit:
client_max_body_size 32m;
client_body_buffer_size 256k;
fastcgi_read_timeout 180s;
În PHP:
upload_max_filesize = 32M
post_max_size = 34M
max_execution_time = 120
max_input_time = 120
Dar adevărata blocare era în aplicație: citea $_FILES și apoi muta fișierul cu move_uploaded_file pe un disc NFS, fără timeout. Am scris fișierul întâi local, apoi l-am copiat asincron:
$tmp = tempnam(sys_get_temp_dir(), 'up_');
if (!move_uploaded_file($_FILES['f']['tmp_name'], $tmp)) {
throw new RuntimeException('upload eșuat');
}
// răspuns imediat, copierea pe NFS o face un worker separat
Mecanismul e simplu: nginx bufferează body-ul pe disc dacă depășește client_body_buffer_size, iar FPM așteaptă să citească tot înainte de a rula scriptul. Dacă aplicația mai și blochează un worker pe I/O lent, coada crește și pentru cererile mici. Am redus request_terminate_timeout la 150s ca să nu acumulez procese moarte, cu prețul că un upload foarte lent e tăiat mai devreme.
Unde se strică: dacă folosești client_body_in_file_only clean, nginx șterge body-ul după ce scriptul îl citește, deci nu poți relua upload-ul. Pe NFS, rename nu e atomic între mount-uri. Și dacă pui post_max_size mai mic decât upload_max_filesize, PHP ignoră fișierul fără eroare vizibilă, doar $_FILES e gol.
Voi cum tratați upload-urile mari când storage-ul final nu e local?


0 条评论
还没有评论,写下第一条。