2015-11-23 10 views
9

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: enter image description here

My status del server apache a così: enter image description here

enter image description here

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 :)

+2

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

+1

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

+0

@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

risposta

3

mod_xsendfile è una buona alternativa per i file che forniscono PHP.

https://tn123.org/mod_xsendfile/

altro si potrebbe aggiungere semplicemente un termine per lo script PHP, quindi non può correre per sempre.

http://php.net/manual/de/function.set-time-limit.php

+0

max_execution_time è già impostato su 2 ore nel mio file php.ini. ho aggiornato la domanda con esso. – hedi

+0

Dovresti davvero considerare mod_xsendfile per il tuo caso d'uso. Un'altra lettura a questo proposito: http://codeutopia.net/blog/2009/03/06/sending-files-better-apache-mod_xsendfile-and-php/ – user5542121

+0

darò un'occhiata, grazie. L'ho provato 2 settimane fa senza successo: serviva file 0kb. – hedi