Skocz do zawartości
Zaloguj się, aby obserwować  
draker

Problem z sendfile w php5-fpm

Polecane posty

Witam,

 

Niedawno przeniosłem większość swoich witryn z Litespeed na nginx z php5-fpm. Wszystko jest OK prócz jednej ze stron, która opiera się na udostępnianiu plików poprzez skrypt PHP. W przypadku Litespeeda wszystko było OK, pliki pobierały się z pełną prędkością i praktycznie nie zużywało to pamięci RAM (z tego co pamiętam, to w ustawieniach miałem ustawioną opcję sendfile na yes). Obecnie gdy ktoś zaczyna pobierać plik z witryny, po wywołaniu skryptu odpowiadającego za wysyłanie pliku dany plik wczytuje się do pamięci RAM (gdy zaczynam pobierać plik ważący 750MB, to zużywa się 750MB RAMu), plik pobiera się z prędkością praktycznie 15kbps, a zużyta pamięć RAM zwalnia się dopiero po ściągnięciu pliku, przez co gdy sporo osób korzysta z witryny, to często zdarza się, że brakuje RAMu. Nie znalazłem w konfiguracji php-fpm opcji do zmiany sposobu wysyłania pliku. Będę wdzięczny za radę, w jaki sposób można zmienić sposób, w jaki nginx / phpfpm wysyła te pliki, by nie zapisywały się one w pamięci RAM, a były wysyłane bezpośrednio z HDD, tak jak to było w przypadku Litespeeda.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Byłbym wdzięczny za pomoc przy zmianie sposobu wysyłania plików na przykładzie mojego skryptu:

 

    if (!$jlistConfig['use.php.script.for.download']){
       if (empty($filename_direct)) {
           $app->redirect($file);
       } else {
           $app->redirect($filename_direct);
       }
   } else {    
       $filename = basename($file);
       $file_extension = strtolower(substr(strrchr($filename,"."),1));
       $ctype = datei_mime($file_extension);
       ob_end_clean();
       // needed for MS IE - otherwise content disposition is not used?
       if (ini_get('zlib.output_compression')){
           ini_set('zlib.output_compression', 'Off');
       }

       header("Cache-Control: public, must-revalidate");
       header('Cache-Control: pre-check=0, post-check=0, max-age=0');
       // header("Pragma: no-cache");  // Problems with MS IE
       header("Expires: 0"); 
       header("Content-Description: File Transfer");
       header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
       header("Content-Type: " . $ctype);
       header("Content-Length: ".(string)$len);
       if (!in_array($file_extension, $view_types)){
           header('Content-Disposition: attachment; filename="'.$filename.'"');
       } else {
         // view file in browser
         header('Content-Disposition: inline; filename="'.$filename.'"');
       }   
       header("Content-Transfer-Encoding: binary\n");
       // redirect to category when it is set the time
       if (intval($jlistConfig['redirect.after.download']) > 0){ 
           header( "refresh:".$jlistConfig['redirect.after.download']."; url=".$redirect_to );
       }    

[...]

 

Czy wystarczy dodać do kodu poniższą linijkę?

header("X-Sendfile: $sciezkadopliku");

jako $ścieżkadopliku musi być bezwzględna ścieżka, czy mogę użyć zmiennej $filename (ale ona chyba odpowiada tylko za nazwę pliku, a nie path)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Teraz zmieniłem kod:

 

if (!in_array($file_extension, $view_types)){

header('Content-Disposition: attachment; filename="'.$filename.'"');

} else {

 

na:

[/color]
if blablabla{
$sciezka2 = '/downloads/'.$cat_dir.'/'.$file_url;
header("X-Accel-Redirect:".$sciezka2);
header('Content-Disposition: attachment; filename="'.$filename.'"');
}else{ blablabla

 

konfig nginx:

location /downloads {
root /home/modbase.pl/public_html;
internal;
}

 

I niestety coś jest nie tak - pobiera się odpowiedni plik o odpowiedniej nazwie, jednak pobierają się puste pliki ważące 5kb zamiast właściwych.

Co jest źle?

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Problemem była $sciezka2, a konkretnie to, ze $file_url i $cat_dir były puste, to juz naprawione, teraz jest dziwniejszy problem. Gdy pobieram plik, pobiera się index.html wskazujący na 500 Internal Server Error, a w logach mam:

 

 

2012/07/18 17:39:52 [error] 23510#0: *20011855 rewrite or internal redirection cycle while internal redirect to "/index.php", client: 31.175.62.69, server: modbase.pl, request: "GET [...]

 

Konfiguracja nginx, a konkretnie mojej strony:

 

server {
       listen 80;
       server_name modbase.pl;
       server_name_in_redirect off;
       client_max_body_size 1024m;
       access_log /home/log/nginx/localhost.access_log;
       error_log /home/log/nginx/localhost.error_log;
       send_timeout 180;
       root /home/modbase.pl/public_html;
       index index.php;
       # Support Clean (aka Search Engine Friendly) URLs
       location / {
       client_max_body_size 1024m;
       try_files $uri $uri/ /index.php?q=$uri&$args break;
       proxy_read_timeout 120;
       send_timeout 180;
       autoindex on;
       }

       index index.php index.html index.htm default.html default.htm;
       # deny running scripts inside writable directories
       location ~* /(images|cache|media|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
               return 403;
               #error_page 403 /403_error.html;
       }

       location ~ .*.php$ {
           include /etc/nginx/fastcgi_params;
fastcgi_connect_timeout 320;

fastcgi_send_timeout 320;
fastcgi_read_timeout 320;
client_max_body_size 1024m;
           fastcgi_pass  127.0.0.1:9000;
           fastcgi_index index.php;
           include fastcgi_params;
send_timeout 180;
           fastcgi_param SCRIPT_FILENAME /home/modbase.pl/public_html$fastcgi_script_name;
       }

location /downloads {
root /home/modbase.pl/public_html;
internal;
}

       # caching of files
       location ~* \.(ico|pdf|flv)$ {
               expires 1y;

       }

       location ~* \.(js|css|png|jpg|jpeg|gif|swf|xml|txt)$ {
               expires 14d;
       }

}

 

Zaraz poszukam czegoś w Google o tym problemie, ale może ktoś już zna odpowiedź

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Masz pętle przekierowań. Po 1 popraw dwa wpisy index w configu. Zostaw tylko 1.

 

Co do pętli to nie mam zbytnio pomysłu, bo nie znam, w którym odbywa się pobieranie. Jeśli wszystko odbywa się po /index.php to może powodować jakiś problem...

 

EDIT:

Możliwe, że pobierasz obrazek, czy plik, który wyłapuje inne wyrażenie location. Na wszelki wypadek spróbuj takiego location, że wykluczyć to co mówię:

][/color]location ^~ /downloads/ {
Edytowano przez Misiek08 (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Wyrzuciłem linię index index.php, ale to raczej kosmetyczny błąd był

 

Napisałem temat na oficjalnym forum nginx'a, może tam ktoś pomoże, bo ja sam nie wiem, gdzie jest ta pętla...

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Ktoś ma jakiś pomysł? Nawet na forum nginx'a nie otrzymałem odpowiedzi...

 

@edit - Misiek, niestety, nic to nie dało, nadal występuje błąd

rewrite or internal redirection cycle while internal redirect

 

Ciekawe, gdzie jest ta błędna pętla i jak na to zaradzić

 

Problem naprawiony, ale nie jestem pewien jak to możliwe.

Odkomentowałem #error_page 403 i wszystko już działa :o

Dodatkowo skrypt PHP wygląda teraz tak:

//$filename_directoo = '/'.$cat_dir.'/'.$file_url;
$sciezka2 = '/downloads/'.$cat_dir.'/'.$file_url;
header("X-Accel-Redirect:".$sciezka2);

Wcześniej używałem $filename_directoo jako ścieżki dla x-sendfile - ale to pewnie bez znaczenia, chyba, że jakimś cudem x-sendfile wymaga po prostu widoczności tego katalogu (/downloads), a nie jakiejś tam zmiennej.

Edytowano przez draker (zobacz historię edycji)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Spróbuj zakomentować ten error i jeśli działa to znaczy, że miałeś błąd w PHP. Co rozumiesz pod:

x-sendfile wymaga po prostu widoczności tego katalogu (/downloads), a nie jakiejś tam zmiennej.
?

Powiedz, bo warto wiedzieć na przyszłość co może sypać błędem.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Jednak to był błąd z PHP, bo zakomentowanie #error nic nie zmienia.

 

Nie wiem dlaczego, ale najwidoczniej x-sendfile wymaga, żeby było tam odrazu /downloads, a nie jako zmienna.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Raczej downloads. Zresztą nie ma się co wgłębiać, jak będzie podobny problem, to albo trzeba zrobić coś z #error, albo zmiany w skrypcie PHP

 

Mimo wszystko kwestia była lepiej rozwiązana w Litespeedzie. Nie wiem, czy trzeba było konfigurować coś jeszcze, ale wydajność x-sendfile jest gorsza od "tego czegoś" z Litespeeda. Pliki nie pobierają się z pełną prędkością łącza, są dziwne spadki prędkości (raz 600bkps, po kilku sekundach 400kbps i tak cały czas), a dopiero po kilku minutach od rozpoczęcia pobierania zaczyna się pobierać normalnie, z pełną prędkością. Natomiast fajne jest to, że można zastosować X-Accel-Limit-Rate - jeszcze tego nie testowałem, ale w łatwy sposób można w skrypcie php ustawić np. limit prędkości dla niezalogowanych, a zalogowani / userzy premium mogą pobierać normalnie - tutaj wystarczy wrzucić jeden header, a w Litespeedzie trzeba było zmieniać sporo linijek w pliku.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Częściowo - miałem licencję darmową, która ma limit bodajże 200-300 req/s, a na serwerze postawiłem jeszcze jedną witrynę, przez co praktycznie przez cały dzień limit był wyczerpywany i czas oczekiwania na wejście na stronę wynosił kilka-kilkanaście sekund, co było bardzo nieciekawe, a jednak $350 rocznie za licencję na kilka stron się nie opłaca, bo żadnego hostingu nie prowadzę :).

 

Przy okazji przed chwilą próbowałem użyć X-Allec-Limit-Rate - trochę mało informacji o tym jest w dokumentacji. W przykładach zazwyczaj podają wartość 1024 - wtedy to mi się plik pobierał z prędkością mniejszą niż 1kbps. Nie mam pojęcia, kto dał ten przykład i dlaczego każdy też go stosuje, bo wtedy nigdy by się nic nie pobrało - po ustawieniu wartości 100000 pobiera się z prędkością 100-121kbps.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach
1024 - wtedy to mi się plik pobierał z prędkością mniejszą niż 1kbps
- po ustawieniu wartości 100000 pobiera się z prędkością 100-121kbps.
I co, nadal nie wiesz w jakich jednostkach jest to podawane? ;)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Jasne że wiedziałem od początku, że w bajtach, bo przecież jest w dokumentacji. Tylko że w we wszelkich dokumentacjach jako przykład podane jest 1024, co mnie zdziwiło, bo z taką prędkością to nigdy by się nic nie pobrało :)

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Na modemie 56k było podobnie i się ściągało małe pliki :P

 

Nginx ma momentami cienką dokumentację, ale przecież można zmienić coś na subdomenie, nginx -t, jak jest ok to nginx -s reload i testujemy.

Udostępnij ten post


Link to postu
Udostępnij na innych stronach

Bądź aktywny! Zaloguj się lub utwórz konto

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto

Zarejestruj nowe konto, to proste!

Zarejestruj nowe konto

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się

Zaloguj się, aby obserwować  

×