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:
Mój status serwera Apache na wygląda tak:
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 :)
ł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
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
@ 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