Ho un grosso problema con un server Apache, l'app php.PHP readfile() non finisce mai e rende il server Apache sospeso
Il server sta servendo un sito Web a traffico piuttosto elevato che è in esecuzione con php.
Ogni 24 ore o 48 ore, apache si blocca e devo riavviarlo per poter accedere nuovamente al sito. Devo riavviarlo, perché apache raggiunge il numero massimo di processi/server consentiti (16000 per me) e non può liberare altri processi perché altri processi sono tutti attivi.
Il sito Web ospitato su questo server è un'app di php, che serve un file alla fine: diciamo che è un server di download.
I file vengono richiesti dal browser tramite un modulo che invia una richiesta POST.
Il problema è che questa richiesta di post sembra non finire mai (posso vedere che quasi tutti i processi di 16000 sullo stato del mio server sono le richieste POST).
I file che vengono serviti sono file di grandi dimensioni (10m a 2G), e li servono con la funzione php readfile (non voglio servire loro con un link href, così ho utilizzare un modulo di richiesta POST in modo che il l'utente non vede mai dove si trova il file sul mio filesystem).
La funzione che utilizza php readfile sembra non finire mai anche se uso exit() alla fine di esso (vedere il codice snipet sotto).
Sto chiedendo qui un modo per evitare queste infinite richieste POST causate dal mio codice php. Voglio mantenere il modo POST di servire i file.
Primo mia conf:
- server di Ubuntu 14.04
- Apache 2.4 con mpm prefork
- php 5.5.9 (php mod)
- hardware: 128G RAM
il mio file mpm_prefork.conf:
<IfModule mpm_prefork_module>
StartServers 512
MinSpareServers 512
MaxSpareServers 1024
ServerLimit 16000 # no problem with my server ram
MaxRequestWorkers 16000
MaxConnectionsPerChild 10000
</IfModule>
mio file apache2.conf:
...
Timeout 300
KeepAlive On
MaxKeepAliveRequests 500
KeepAliveTimeout 5
...
il mio PHP.file ini:
max_execution_time = 7200
miei file di log di Apache: nulla di interessante per il mio problema
Un grafico Munin che mostra quando il problema si verifica:
My status del server apache a così:
E la mia classe di server (il codice che causa il problema):
class Server
{
/* the file is served from a remote url source */
public function serveFileFromUrl()
{
if (empty($_POST)) {
return;
}
$url = $_POST['file_url'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
/* file is served from my filesystem */
public function serveFileFromPath()
{
if (empty($_POST)) {
return;
}
$url = APP_PATH . '/download/' . $_POST['file_name'];
$mime = $_POST['mime'];
$name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime;
$size = $_POST['size'];
if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
// for Internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header("Content-Transfer-Encoding: binary");
header('Pragma: public');
} else {
// not for internet Explorer
if ($mime == 'mp3') {
header('Content-Type: "audio/' . $mime . '"');
} else {
header('Content-Type: "video/' . $mime . '"');
}
header('Content-disposition: attachment; filename="' . $name . '"');
header('Expires: 0');
if ($size !== '') {
header('Content-Length: ' . $size);
}
header("Content-Transfer-Encoding: Binary");
header('Pragma: no-cache');
}
ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile)
flush(); // fix memory problems with readfile
readfile($url);
@ob_end_flush();
exit();
}
}
fa qualcuno ha una soluzione per evitare le infinite richieste POST? Sto bene a servire i file tramite altra cosa rispetto a php se può risolvere il problema.
Si prega di non duplicato, ho aggiunto il codice abbastanza, frammento e le immagini conf per fare questa domanda specifica :)
un modo semplice per sbarazzarsi del 50% di tale codice sarebbe quello di sostituire la parte serveFileFromUrl() con un reindirizzamento HTTP, alias intestazione Posizione. potrebbe anche risolvere il tuo problema con un po 'di fortuna. – Calimero
Hai impostato il tuo limite di tempo su 0. Dont. Non è sicuramente una soluzione, ma impostala qualcosa come 10 ore, manterrà in vita il tuo server anche se qualcosa fallisce come fa ora e, molto probabilmente, non farà casino con quello che fai. Imposta il doppio del tempo in cui pensi che uno script avrebbe preso. – Elentriel
@Calimero se utilizzo solo la posizione dell'intestazione, il file (questo è un file video) viene riprodotto nel browser. Voglio che il file sia scaricato. – hedi