apache2 și performanța

sâmbătă, 7 ian. 2012, 18:06

Săptămâna asta am avut ocazia să pun mâna pe niște cunoștințe foarte utile în cadrul unui curs din facultatea aia unde nu se predă nimic care să aibă utilitate practică. Întâmplător cunoștințele cu pricina chiar s-au dovedit a-mi fi utile spre a înțelege mai bine cum funcționează serverele web și cum să le gestionez cât de cât eficient pe mașina proprie, mașină pe care sunt găzduite și cărămizile. Astfel, dat fiind faptul că avem studiul de caz deja pregătit, vă pot împărtăși o parte din cunoștințele acumulate fără prea mare efort.

Web-ul constă – dedesubtul sferei abstracte formate din tot felul de buzzword-uri care mai de care mai cu sclipici, la nivelul său cel mai de jos – în servicii care oferă și eventual primesc informație peste protocolul HTTP. Toate bune și frumoase, însă dacă stăm și cugetăm un moment, realizăm că acele servicii rulează pe mașini fizice, care au peste ele sisteme de operare, care oferă protecție și flexibilitate, asigură (sau nu) performanța și așa mai departe.

De exemplu site-ul de față rulează pe o mașină având instalată un server web Apache2, peste un Debian care rulează pe un hardware ce constă în mare dintr-un procesor rulând la 800MHz, cu un cache de 256KB și o memorie RAM de 512MB. Mașina asta trebuie să livreze un număr de site-uri, multe din ele implementate în PHP, într-un timp finit suficient de mic, pentru a asigura că utilizatorul nu moare de bătrânețe, sau mai degrabă de plictiseală, așteptând să se încarce pagina. Iar dacă la nivelul WordPress-ului treaba se rezolvă destul de ușor printr-un plugin de caching, la nivelul aplicației și al sistemului de operare treaba nu stă chiar așa de simplu.

Apache2 pune la dispoziția utilizatorului mai multe module pentru servirea propriu-zisă, module numite pe scurt MPM (Multi-Processing Modules). Acestea implementează în esență felul în care este făcută servirea în cadrul sistemului de operare, mai exact numărul de procese sau thread-uri folosite și alte detalii precum felul în care firele de execuție ascultă pe sockeți [i]. Zisele module sunt astfel esențiale pentru performanța și scalabilitatea server-ului web.

Modulul implicit folosit de Apache2 pe debian este mpm-prefork, care execută din capul locului un număr de procese (implicit cinci, urmând să îl crească la zece pe măsura creșterii load-ului), asigurând astfel că servirea se va face în paralel [ii]. Strategia e evident eficientă dacă ne gândim un pic la ceea ce ne spun cărțile de sisteme de operare [iii]: execuția proceselor ia ceva timp – timpii necesari creării spațiului de adresă și a altor structuri de date aferente procesului, timpul necesar alocării stivei și așa mai departe -, astfel că e esențial ca server-ul să aibă procesele deja create și să le utilizeze când este necesar.

Pe de altă parte un sistem având 512MB RAM va suferi de pe urma creării mai multor procese, pentru că fiecare proces induce un overhead de spațiu, tradus prin mărirea memory footprint-ului. Soluția mai eficientă ar fi utilizarea modulului mpm-worker, care merge și pe mai multe thread-uri, asigurând nu numai un consum mai mic de memorie, ci și o scalabilitate mai mare. Buba mare a lui mpm-worker e că nu merge cu modulul Apache pentru PHP, fiind necesară execuția PHP prin FastCGI, deci implicit editarea fișierelor de configurare a tuturor site-urilor care execută cod PHP.

Soluția cea mai rapidă este configurarea mpm-prefork din /etc/apache2/apache2.conf la următoarele valori:

<ifmodule mpm_prefork_module>
    StartServers                    3
    MinSpareServers            3
    MaxSpareServers           5
    MaxClients                       100
    MaxRequestsPerChild   0
</ifmodule>

Directivele de mai sus îi specifică server-ului să înceapă cu trei procese prealocate și să crească numărul la cinci (în loc de numărul implicit zece) în caz de nevoie. În plus, la nevoie se pot deschide până la o sută de procese simultan, indiferent de numărul de procese prealocate, iar numărul maxim de cereri simultane e nelimitat. De remarcat că soluția afectează negativ performanța timpilor de servire (deoarece se vor crea mai multe procese temporare), în timp ce asigură că paginile din RAM o să rămână cât de cât stabile, adică nu se va ajunge la swapping cu una cu două – caz de altfel dezastruos din orice punct de vedere. Ideea reprezintă însă un compromis necesar pentru un sistem fizic atât de sărac.

În viitor voi experimenta probabil și cu mpm-worker, iar planul pe termen lung îl reprezintă trecerea la nginx, care are avantajul că folosește ascultare bazată pe evenimente [iv] și e în general mai lightweight decât Apache. În fine, cei care doresc într-adevăr un server web scalabil nu vor putea obține rezultate satisfăcătoare decât pe un sistem hardware cu multe core-uri și RAM de ordinul GB. Și cu o sursă țeapănă, pentru a nu avea parte de surprize la prima fluctuație de tensiune pe rețeaua electrică.

  1. Aici discuția devine amplă, pentru că putem avea un singur fir de execuție care ascultă și care apoi expediază task-ul către alte thread-uri, iar ascultarea se poate face fie folosind select, fie folosind alte metode asincrone etc., nu are rost să intrăm în detalii acum. []
  2. Cu pseudo- în față în cazul unui sistem uniprocesor cum este mașina descrisă mai sus. []
  3. Silberschatz, Galvin, Gagne: Operating System Concepts. []
  4. Apache2 are mpm-event care este însă experimental în momentul de față. []

Comentariile sunt dezactivate.