2015-11-23 15 views
9

Mam duży problem z serwerem apache, aplikacją php.PHP readfile() nigdy się nie kończy i sprawia, że ​​serwer Apache się zawiesił

Serwer obsługuje dość wysoką stronę internetową o ruchu, która działa z php.

Co 24 godziny lub 48 godzin, apache się zawiesza i muszę go zrestartować, aby móc ponownie uzyskać dostęp do witryny. Muszę go zrestartować, ponieważ apache osiąga maksymalną liczbę dozwolonych procesów/serwerów (16000 dla mnie) i nie może zwolnić innych procesów, ponieważ inne procesy są wszystkie aktywne.

Witryna hostowana na tym serwerze to aplikacja php, która wyświetla plik na końcu: powiedzmy, że jest serwerem pobierania.

Pliki są pobierane przez przeglądarkę za pomocą formularza, który przesyła żądanie POST.

Problem polega na tym, że ten post wydaje się nigdy nie kończyć (widzę, że prawie wszystkie 16000 procesów na moim stanie serwera to żądania POST).

Pliki, które są obsługiwane, to duże pliki (od 10M do 2G), i serwuję je z funkcją php readfile (nie chcę obsługiwać ich za pomocą odnośnika href, więc używam formularza żądania POST, aby użytkownik nigdy nie widzi, gdzie plik znajduje się w moim systemie plików).

Funkcja korzystająca z php readfile wydaje się nigdy się nie kończyć, nawet jeśli użyję exit() na końcu (zobacz kod snipet poniżej).

Proszę tutaj o sposób na uniknięcie niekończących się żądań POST spowodowanych przez mój kod php. Chcę zachować POST do udostępniania plików.

Pierwszy mój conf:

  • serwer Ubuntu 14.04
  • Apache 2.4 z MPM prefork
  • PHP 5.5.9 (mod php)
  • sprzętu: 128g RAM

mój plik 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> 

mój plik apache2.conf:

... 
Timeout 300 
KeepAlive On 
MaxKeepAliveRequests 500 
KeepAliveTimeout 5 
... 

Moje php.ini:

max_execution_time = 7200 

moje logi apache: nic ciekawego do mojego problemu

wykres munin który pokazuje, kiedy problem się dzieje: enter image description here

Mój status serwera Apache na wygląda tak: enter image description here

enter image description here

A moja klasa serwera (kod, który jest przyczyną problemu):

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(); 
    } 
} 

Czy ktoś ma rozwiązanie, aby uniknąć niekończąca żądania POST? Jestem w porządku, aby serwować pliki za pośrednictwem innych rzeczy niż php, jeśli to rozwiąże problem.

proszę nie duplikat, dodałem tyle kodu, conf fragment i zdjęcia, aby ten konkretny pytanie :)

+2

łatwym sposobem, aby pozbyć się 50% tego kodu byłoby wymienić serveFileFromUrl() część z przekierowania HTTP, aka nagłówka Location. może nawet naprawić twój problem przy odrobinie szczęścia. – Calimero

+1

Ustawiłeś swój timelimit na 0. Nie. To zdecydowanie nie jest poprawka, ale ustaw to na około 10 godzin, to utrzyma twój serwer przy życiu, nawet jeśli coś się nie powiedzie, tak jak teraz i to, najprawdopodobniej, nie zadzieraj z tym, co robisz. Ustaw dwukrotnie więcej czasu, niż myślisz, że skrypt zajmie. – Elentriel

+0

@ Calimero, jeśli używam tylko nagłówka Lokalizacja, plik (jest to plik wideo) jest odtwarzany w przeglądarce. Chcę, aby plik został pobrany. – hedi

Odpowiedz

3

mod_xsendfile jest dobrą alternatywą dla PHP dostarczania plików.

https://tn123.org/mod_xsendfile/

jeszcze można po prostu dodać termin ostateczny do skryptu PHP, więc nie może działać wiecznie.

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

+0

max_execution_time jest już ustawiona na 2 godziny w moim plik php.ini. zaktualizowałem to pytanie. – hedi

+0

Powinieneś naprawdę rozważyć mod_xsendfile dla twojego przypadku użycia. Inny czytał o tym: http://codeutopia.net/blog/2009/03/06/sending-files-better-apache-mod_xsendfile-and-php/ – user5542121

+0

Spójrz, dzięki. Próbowałem go 2 tygodnie temu bez powodzenia: serwował pliki 0kb. – hedi

Powiązane problemy