FastCGI jest bardzo często kojarzone wyłącznie z Perl’em lub PHP, w przypadku serwera Lighttpd, użycie FastCGI jest jedynym sposobem aby zmusić go do pracy z PHP, ale musimy wiedzieć, że jest niezależne od języka programowania i serwera WWW, jest to raczej coś w rodzaju sposobu komunikacji pomiędzy serwerem a aplikacją (pomostem). Zasadniczą różnicą pomiędzy CGI a FastCGI jest wydajność, która została znacznie podniesiona poprzez wyeliminowanie konieczności uruchamiania skryptu/aplikacji przy każdym odwołaniu. W przypadku CGI serwer WWW otrzymując żądanie od przeglądarki uruchamiał „na boku” aplikację i zwracał wynik, natomiast dzięki FastCGI istnieje możliwość uruchomienia konkretnej liczby instancji aplikacji, które w trybie ciągłym oczekują na wywołanie bez konieczności każdorazowego uruchamiania procesu.
Przewagą FastCGI nad CGI może być również to, że uruchomiona aplikacja jest w stanie przechowywać różne wartości w pamięci do których możemy się odwołać w dowolnym momencie, w przypadku CGI nie było to możliwe, ponieważ po obsłużeniu każdego żądania proces umierał i zawartość buforów była tracona.
Procesy FastCGI (aplikacje) są całkowicie niezależne od serwera, po prostu działają obok, a to zdecydowanie utrudnia wywołanie awarii w której padnie serwer WWW.
Jeśli chodzi o skalowanie, to sprawa wygląda tak, że serwer WWW otrzymuje request od użytkownika i przekazuje go w pełni do aplikacji fcgi, w serwerze WWW możemy określić w jaki sposób ma nastąpić połączenie (np. socket, lub tcp), dzięki temu możemy mieć odseparowane aplikacje od warstwy HTTP.
Spróbujmy napisać i uruchomić prostą aplikację FastCGI w C (Lighttpd + Ubuntu):
Instalacja niezbędnej biblioteki libfcgi do obsługi FastCGI w ANSI C
# apt-get install libfcgi-dev
Konfiguracja serwera Lighttpd:
# cat /etc/lighttpd/conf-enabled/10-fastcgi.conf
server.modules += ( „mod_fastcgi” )fastcgi.server = ( „.fcgi” =>
((
„bin-path” => „/tmp/app-cgi”,
„socket” => „/tmp/cgi.socket”,
„max-procs” => 4,
„check-local” => „disable”,
„bin-copy-environment” => (
„PATH”, „SHELL”, „USER”
),
))
)
- server.modules – taki zapis pozwala na dodanie do listy modułów, modułu mod_fastcgi
- fastcgi.server – „.fcgi” – określa dla których rozszerzeń żądanie ma być przekazane do aplikacji fcgi
- bin-path – ścieżka do naszej aplikacji
- socket – ściezka do socketu po których będzie odbywała się komunikacja (lighttpd -> fcgi), istnieje również możliwość komunikacji po tcp, wtedy nasza aplikacja fcgi może być uruchomiona na zdalnym serwerze (klastrze)
- max-procs – maksymalna liczba procesow naszej aplikacji fcgi
- idle-timeout – czas bezczynności
- check-local – jeśli jest enable, to serwer lighttpd będzie najpierw szukał pliku ihha.fcgi w document.root serwera, jeśli nie znajdzie to zwróci 404, natomiast jeśli jest ustawiona na disable to przekaże od razu request do aplikacji fcgi
- bin-copy-environment – pozwala na kopiowanie wartości zmiennych środowiskowych (PATH, SHELL, USER)
Kod naszej aplikacji:
#include "fcgi_stdio.h" #include <stdlib.h> int count; void main(void) { count = 0; while (FCGI_Accept() >= 0) { printf("Content-type: text/html\r\n\r\n" "<h1>FastCGI App!</h1>" "Request: %d <br />" "PID: %d", ++count, getpid()); } }
- #include „fcgi_stdio.h” – plik nagłówkowy dla fcgi
- int count – deklaracja zmiennej count – licznika obsłużonych żądań (dla każdego procesu app-cgi jest unikalny)
- while (FCGI_Accept() >= 0) – pętla główna naszej aplikacji (specyficzne dla fastcgi, ponieważ aplikacja nie kończy działania)
- printf(„Content-type: text/html”) – wysyłamy nagłówek HTTP mówiący o tym, że kontent będzie danymi w postaci text/html (lighttpd przekazuje całe żądanie do aplikacji fastcgi, tak więc aplikacja musi odpowiedzieć wraz z nagłówkami, ten jest niezbędny aby wyświetlić tekst w przeglądarce)
- ++count, getpid() – inkrementacja licznika count oraz pobranie pidu procesu (argumenty dla printf(%d %d))
Kompilacja odbywa się w następujący sposób:
# gcc /tmp/cgi-app.c -lfcgi -o /tmp/app-cgi
- -lfcgi – mówi kompilatorowi by zlinkował nasz program app-cgi z biblioteką fcgi
# ldd /tmp/app-cgi
linux-gate.so.1 => (0x0070c000)
libfcgi.so.0 => /usr/lib/libfcgi.so.0 (0x00ef8000)
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00ce9000)
libnsl.so.1 => /lib/tls/i686/cmov/libnsl.so.1 (0x005fc000)
libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0×00234000)
/lib/ld-linux.so.2 (0×00665000)
Mając skompilowaną aplikację i skonfigurowany serwer WWW możemy spróbować uruchomić całość:
# /etc/init.d/lighttpd restart
Dodatkowo możemy sprawdzić czy nasza aplikacja FCGI została poprawnie zespawnowana:
# pstree | grep lighttpd
|-lighttpd—4*[app-cgi]
Widzimy 1 proces lighttpd i dodatkowe 4 procesy app-cgi ;-) czyli wszystko gra. Pobieramy stronę:
$ lwp-request http://192.168.1.194/app.fcgi
<h1>FastCGI App!</h1>Request: 1 <br />PID: 11282
Wszystko działa poprawnie, serwer nam zwrócił numer requestu: 1 dla konkretnego procesu app-cgi (PID). W przypadku dużego ruchu, Lighttpd rozrzuci ruch pomiędzy 4 procesy app-cgi, ale należy pamiętać, że zmienne aplikacji są tylko w obrębie jednego procesu – count dla każdego procesu app-cgi będzie inny.
Czy jest sens używania FastCGI? Oczywiście, że tak. W wielu zastosowaniach taka aplikacja będzie dużo bardziej wydajna niż skrypt napisany w PHP, czasami nie ma potrzeby zaprzęgania całego interpretera PHP czy Perl, do wykonania jakiejś prostej czynności, wszyscy przecież wiemy, że Linuks lubi C. ;-)
A Wy korzystacie z FastCGI? albo widzicie jakieś ciekawe zastosowanie?






Zawsze wszyscy mnie uczyli, że cgi jest ble (np bo niebezpieczne, nigdy w tym nie pisałem zawsze all w php).
Ale widzę, że pewnie wszyscy będą myśleli, że jestem ignorantem.
Dużo ludzi używa CGI ?
CGI można napisać praktycznie we wszystkim – nie szukam tutaj flame’a ;) możesz też napisać je w PHP. Prawda jest taka, że w zależności jak uruchamiany jest interpreter PHP może się okazać, że przy innych serwerach niż Apache Twój kod w PHP uruchamiany jest przez (Fast|Ultra)CGI. Patryk wyjaśnił jakie są różnice pomiędzy zwykłym, a szybszym CGI.
W moim odczuciu część ludzi mówi, że „cgi jest ble” bo w CGI kiedyś pisało się głównie w C, Perlu, a są to języki, przy których trzeba uważać na jeszcze inne klasy błędów bezpieczeństwa niż przy samym PHP. C w rękach mało wnikliwego programisty na poziomie pracy z pamięcią procesu jest bardzo kontuzjogenne i może prowadzić do bardzo poważnych błędów. Natomiast aplikacja w C prawie zawsze będzie szybsza od aplikacji w PHP – za to prawie zawsze będzie pisana dłużej.
Wszystko ma swoje zastosowanie – lepsze albo gorsze.