Apache 2+mod_fcgid – setup rapid pentru test/dezvoltare
Posted in: Administrare, Linux, By: SaltwaterC, At: May 25th, 2010
Apache 2 + mod_php, ceea ce în majoritatea cazurilor implică prefork MPM, este un setup cretin. Am spus-o, o mai spun și o susțin, cu toate că acest setup este implicit sub *nix. Dacă memoria este oarecum un lux, sau nu ai trecut deja pe un web server cu o arhitectură asincronă, atunci agonia cu Apache se mai poate prelungi puțin, apelând la worker MPM + mod_fcgid + PHP rulat ca FastCGI. O să fac doar o scurtă mențiune despre faptul că arhitectura multiproces / multithread din punctul de vedere al scalabilității este moartă, oricât ai face “yet another Apache smart-ass tweak”. Problema nu este în viteza efectivă a soft-ului ci în arhitectura în sine. Să mai zic ceva de Slowloris?
Bun. Mi-am mai vărsat încă o dată anii de frustrare acumulați cu Apache, deci trebuie să pun și partea productivă în schemă. Sub Debian & friends se rezolvă simplu cu un:
apt-get -y install libapache2-mod-fcgid
a2dismod php5
a2enmod fcgid
/etc/init.d/apache2 force-reload
apt-get -y install php5-cgi
Cam atât pe partea de instalare. Cei ce suferă cu RHEL/CentOS, pot apela cu încredere la EPEL. Sau să compileze din surse. Nu o să îmi vărs în acest articol frustrările acumulate cu tandemul de mai sus.
Pe partea de configurare, integrarea dintre Apache + mod_fcgid + php-cgi lipsește cu desăvârșire ceea ce poate să dezamăgească mulțimea “kewl, I just installd Lenux and PHP”. Dar nu e nici “rocket science”. Ca idee: nano /etc/apache2/mods-enabled/fcgid.conf iar pe post de conținut:
<IfModule mod_fcgid.c>
AddHandler fcgid-script .fcgi .php
DefaultInitEnv PHPRC /etc/php5/cgi
DefaultInitEnv PHP_FCGI_MAX_REQUESTS 10000
MaxRequestsPerProcess 10000
MaxProcessCount 10
IPCCommTimeout 240
IdleTimeout 240
FCGIWrapper /usr/bin/php-cgi .php
AddType application/x-httpd-php .php
</IfModule>
Aceasta este sintaxa “sigură”, deși ultimele versiuni ale mod_fcgid includ o sintaxă nouă iar cea veche este marcată ca “deprecated”. Pentru cei cu Ubuntu 10.04 LTS sau o altă distribuție relativ nouă, sintaxa actualizată este următoarea:
<IfModule mod_fcgid.c>
AddHandler fcgid-script .fcgi .php
FcgidInitialEnv PHPRC /etc/php5/cgi
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 10000
FcgidMaxRequestsPerProcess 10000
FcgidMaxProcesses 10
FcgidIOTimeout 240
FcgidIdleTimeout 240
FcgidWrapper /usr/bin/php-cgi .php
AddType application/x-httpd-php .php
</IfModule>
Atenție: nu va funcționa pe versiunile vechi de mod_fcgid!
Încă puțin și setup-ul este gata de bătaie. Mai trebuie adăugat un flag în Options pentru a permite execuția PHP-ului sub FastCGI, sau serverul va returna 403. Fie se adaugă pentru fiecare definiție <Directory> din virtual host (nu e nevoie pentru <Directory /> în anumite cazuri) sau din .htaccess. Teoretic Options, conform documentației, poate fi setat în context <VirtualHost>, dar practic existența unui <Directory> cu Options o invalidează. Se poate seta doar pentru <Directory /> dacă toate celelalte definiții <Directory> nu au directiva Options. Pe scurt: Options funcționează pe ideea de arbore, dacă un fiu folosește Options, nu se mai moștenește părintele. Alternativa simplă și fără bătaie de cap, repet, pentru test/dezvoltare, este .htaccess cu Options +ExecCGI. Sub Ubuntu Hardy Options ExecCGI a refuzat să funcționeze din .htaccess, deci e mai sigur să fie prefixat cu +. Am repetat ce am zis în titlu pentru simplul fapt că .htaccess în producție se pretează doar unui mediu partajat ce este vândut de către companiile de hosting. În rest e risc potențial de securitate, în special pentru cele auto-generate (+ implicații la nivel de permisiuni), și supra-încărcare inutilă a serverului din moment ce Apache este mai țăran din fire și nu este notificat de schimbarea fișierului ci îl citește la fiecare cerere. În plus, un setup de producție făcut după “manualul de securitate” presupune configurare per virtual host și suEXEC versus rularea sub userul web serverului și un singur Dumnezeu pentru toate fișierele.
Din punctul de vedere al eficienței, în idle (după restartul serviciului) cu setup-ul implicit sub Ubuntu Hardy:
<IfModule mpm_worker_module>
StartServers 2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild 25
MaxRequestsPerChild 0
</IfModule>
și un singur PHP upstream, am obținut un record de memory footprint pentru Apache 2: 18MiB.
Bun asa. Am ajuns aici pe materialul cu nginx si acum ma bucur ca m-am uitat sa vad ce ai mai scris.
Eram si eu unul din fericitii castigatori ai configuratiei apache+mod_php pana cand n-am mai suportat si am facut switch la nginx.
O sa testez azi si varianta propusa de tine, dar intre timp ma gandesc ca nu strica sa verific si alta opinie: intre varianta descrisa aici si nginx cu phpfcgi are Apache sanse sa se comporte macar comparabil?
Nu prea. Am migrat către nginx și PHP-FPM fără prea multă dorință de întoarecere, exceptând poate momentele în care înjur vreun incompetent ce a făcut o aplicație “for Apache” cu sute de reguli de rewrite, fără să îi fi dat prin cap de ce majoritatea engine-urilor decente folosesc front controller pattern design. Chiar și așa, am scris un script ce face conversia Apache to nginx, dar încă necesită perfecționare înainte să-l prezint lumii sub formă de aplicație. Pe serverele de producție, ultimul deploy de Apache+mod_php pe care îl mai am, se pregătește să moară.
Apache nu are cum să se comporte comparabil. Are “tradiție” și e destul de robust, uneori de neînlocuit pentru anumite tipuri de aplicații (încă-l folosesc pentru servirea de SVN), dar are o arhitectură din categoria “brain dead”, deci mai devreme sau mai târziu se va lovi de limita de memorie, e drept, mult mai târziu dacă rulează ca worker MPM. Am sperat că event MPM pentru Apache (încă experiental) va aduce un suflu de prospețime peste LAMP, dar din studiile mele, este mai prost ca opțiune față de worker. E un fel de hibrid de hibrid. Știu suficienți aplaudaci de Apache ce susțin varii tips & tricks, “install mod_smartass for 1% performance gain”, dar după ani de administrat Apache+PHP, aceste chestii arată mai puțin a configurare de server și mai mult a “turd polishing”.
Pentru că am menționat de studii, am aici un performance report ce va deveni cândva un articol despre web servere + PHP, axat mai mult pe experiența cu fiecare și mai puțin pe performanță (contrar aparențelor din document). Motivul a fost și imposibilitatea de a testa scenarii multiple mai relevante din punctul de vedere al performanței datorită numărului consistent de platforme și durata unui test propriu zis.
PS: singurul web server decent cu arhitectură multithread este Hiawatha și eventual singurul server open source din categoria “lightweight” pe care l-aș alege în detrimentul nginx. De fapt chiar foarte rapid pentru obiecte statice, dar nu se pretează ca proxy (autorul a zis strict web server), decent pentru FastCGI, relativ simplu de configurat, dar momentan cu un bug ce pentru mine e show stopper: http://www.hiawatha-webserver.org/forum/topic/625 – dar încă lucrez cu autorul pentru rezolvarea lui (deși momentan autorul e foarte ocupat, o să apară cândva și un patch).