Rendiment d'aplicacions de xarxa Linux. Introducció
Ara les aplicacions web s'utilitzen a tot arreu i, entre tots els protocols de transport, HTTP ocupa la part del lleó. Quan s'estudien els matisos del desenvolupament d'aplicacions web, la majoria de la gent presta molt poca atenció al sistema operatiu on s'executen aquestes aplicacions. La separació de desenvolupament (Dev) i operacions (Ops) només va empitjorar la situació. Però amb l'auge de la cultura DevOps, els desenvolupadors s'estan convertint en els responsables d'executar les seves aplicacions al núvol, per la qual cosa és molt útil que es familiaritzin a fons amb el backend del sistema operatiu. Això és especialment útil si esteu intentant desplegar un sistema per a milers o desenes de milers de connexions simultànies.
Les limitacions dels serveis web són molt semblants a les d'altres aplicacions. Tant si es tracta d'equilibradors de càrrega com de servidors de bases de dades, totes aquestes aplicacions tenen problemes similars en un entorn d'alt rendiment. Comprendre aquestes limitacions fonamentals i com superar-les en general us ajudarà a avaluar el rendiment i l'escalabilitat de les vostres aplicacions web.
Escric aquesta sèrie d'articles com a resposta a preguntes de joves desenvolupadors que volen convertir-se en arquitectes de sistemes ben informats. És impossible entendre clarament les tècniques d'optimització d'aplicacions Linux sense capbussar-se en els conceptes bàsics de com funcionen a nivell de sistema operatiu. Tot i que hi ha molts tipus d'aplicacions, en aquesta sèrie vull explorar aplicacions basades en web en lloc d'aplicacions d'escriptori com ara un navegador o un editor de text. Aquest material està pensat per a desenvolupadors i arquitectes que volen entendre com funcionen els programes Linux o Unix i com estructurar-los per a un alt rendiment.
Linux ho és sala de servidors sistema operatiu, i la majoria de les vostres aplicacions s'executen en aquest sistema operatiu. Encara que dic "Linux", la majoria de les vegades podeu suposar amb seguretat que em refereixo a tots els sistemes operatius semblants a Unix en general. Tanmateix, no he provat el codi adjunt en altres sistemes. Per tant, si esteu interessats en FreeBSD o OpenBSD, els vostres resultats poden variar. Quan intento alguna cosa específica de Linux, ho assenyalo.
Tot i que podeu utilitzar aquest coneixement per crear una aplicació des de zero i estarà perfectament optimitzada, el millor és no fer-ho. Si escriviu un nou servidor web en C o C++ per a l'aplicació empresarial de la vostra organització, aquest pot ser el vostre darrer dia a la feina. Tanmateix, conèixer l'estructura d'aquestes aplicacions ajudarà a triar els programes existents. Podreu comparar sistemes basats en processos amb sistemes basats en fils i altres basats en esdeveniments. Entendreu i apreciareu per què Nginx funciona millor que Apache httpd, per què una aplicació Python basada en Tornado pot servir a més usuaris en comparació amb una aplicació Python basada en Django.
ZeroHTTPd: eina d'aprenentatge
ZeroHTTPd és un servidor web que vaig escriure des de zero en C com a eina d'ensenyament. No té dependències externes, inclòs l'accés a Redis. Executem els nostres propis tràmits Redis. Vegeu a continuació per obtenir més detalls.
Tot i que podríem parlar de teoria llargament, no hi ha res millor que escriure codi, executar-lo i comparar totes les arquitectures de servidors entre si. Aquest és el mètode més evident. Per tant, escriurem un servidor web ZeroHTTPd senzill utilitzant cada model: basat en processos, basat en fils i basat en esdeveniments. Mirem cadascun d'aquests servidors i veiem com funcionen en comparació. ZeroHTTPd s'implementa en un únic fitxer C. El servidor basat en esdeveniments inclou uthash, una excel·lent implementació de la taula hash que inclou un únic fitxer de capçalera. En altres casos, no hi ha dependències, per no complicar el projecte.
Hi ha molts comentaris al codi per ajudar-vos a entendre. En ser un simple servidor web en poques línies de codi, ZeroHTTPd també és un marc mínim per al desenvolupament web. Té una funcionalitat limitada, però és capaç de servir fitxers estàtics i pàgines "dinàmiques" molt senzilles. He de dir que ZeroHTTPd és bo per aprendre a crear aplicacions Linux d'alt rendiment. En general, la majoria de serveis web esperen les sol·licituds, les revisen i les processen. Això és exactament el que farà ZeroHTTPd. Aquesta és una eina d'aprenentatge, no de producció. No és genial en la gestió d'errors i és poc probable que tingui les millors pràctiques de seguretat (oh, sí, vaig utilitzar strcpy) o els trucs intel·ligents del llenguatge C. Però espero que faci bé la seva feina.
Pàgina d'inici de ZeroHTTPd. Pot produir diferents tipus de fitxers, incloses imatges
Aplicació del llibre de visites
Les aplicacions web modernes normalment no es limiten a fitxers estàtics. Tenen interaccions complexes amb diverses bases de dades, cachés, etc. Així que crearem una senzilla aplicació web anomenada "Guest Book" on els visitants deixen entrades sota el seu nom. El llibre de visites emmagatzema les entrades deixades abans. També hi ha un comptador de visitants a la part inferior de la pàgina.
Aplicació web "Llibre de visites" ZeroHTTPd
El comptador de visites i les entrades del llibre de visites s'emmagatzemen a Redis. Per a les comunicacions amb Redis, s'implementen procediments propis, no depenen de la biblioteca externa. No sóc un gran fan de llançar codi homebrew quan hi ha solucions disponibles públicament i ben provades. Però l'objectiu de ZeroHTTPd és estudiar el rendiment de Linux i l'accés a serveis externs, mentre que atendre sol·licituds HTTP té un impacte greu en el rendiment. Hem de controlar totalment les comunicacions amb Redis en cadascuna de les nostres arquitectures de servidor. En algunes arquitectures fem servir trucades de bloqueig, en d'altres fem servir procediments basats en esdeveniments. L'ús d'una biblioteca de client Redis externa no proporcionarà aquest control. A més, el nostre petit client Redis només realitza unes quantes funcions (obtenir, configurar i augmentar una clau; obtenir i afegir-hi una matriu). A més, el protocol Redis és extremadament elegant i senzill. Ni tan sols cal ensenyar-ho especialment. El fet mateix que el protocol faci tota la feina en un centenar de línies de codi mostra el ben pensat que està.
La figura següent mostra què fa l'aplicació quan el client (navegador) ho sol·licita /guestbookURL.
Com funciona l'aplicació del llibre de visites
Quan cal emetre una pàgina del llibre de visites, hi ha una trucada al sistema de fitxers per llegir la plantilla a la memòria i tres trucades de xarxa a Redis. El fitxer de plantilla conté la major part del contingut HTML de la pàgina de la captura de pantalla anterior. També hi ha marcadors especials per a la part dinàmica del contingut: publicacions i comptador de visitants. Els rebem de Redis, els inserim a la pàgina i proporcionem al client un contingut totalment format. La tercera trucada a Redis es pot evitar perquè Redis retorna el nou valor de clau quan s'incrementa. Tanmateix, per al nostre servidor, que té una arquitectura asíncrona basada en esdeveniments, moltes trucades de xarxa són una bona prova per a finalitats d'aprenentatge. Per tant, descartem el valor de retorn de Redis del nombre de visitants i el consultem amb una trucada independent.
Arquitectures de servidor ZeroHTTPd
Estem construint set versions de ZeroHTTPd amb la mateixa funcionalitat però amb arquitectures diferents:
Iteratiu
Servidor de bifurcació (un procés secundari per sol·licitud)
Servidor de pre-bifurcació (pre-bifurcació de processos)
Servidor amb fils d'execució (un fil per sol·licitud)
Servidor amb creació prèvia al fil
Basat en l'arquitectura poll()
Basat en l'arquitectura epoll
Mesurem el rendiment de cada arquitectura carregant el servidor amb peticions HTTP. Però quan es comparen arquitectures molt paral·leles, el nombre de consultes augmenta. Fem tres proves i calculem la mitjana.
Metodologia de prova
Configuració de la prova de càrrega ZeroHTTPd
És important que quan s'executen proves, no tots els components s'executen a la mateixa màquina. En aquest cas, el sistema operatiu comporta una sobrecàrrega de programació addicional a mesura que els components competeixen per la CPU. Mesurar la sobrecàrrega del sistema operatiu de cadascuna de les arquitectures de servidor seleccionades és un dels objectius més importants d'aquest exercici. Afegir més variables serà perjudicial per al procés. Per tant, la configuració de la imatge anterior funciona millor.
Què fa cadascun d'aquests servidors?
load.unixism.net: aquí és on correm ab, Utilitat Apache Benchmark. Genera la càrrega necessària per provar les nostres arquitectures de servidor.
nginx.unixism.net: De vegades volem executar més d'una instància d'un programa de servidor. Per fer-ho, el servidor Nginx amb la configuració adequada funciona com a equilibrador de càrrega procedent ab als processos del nostre servidor.
zerohttpd.unixism.net: aquí executem els nostres programes de servidor en set arquitectures diferents, una a la vegada.
redis.unixism.net: aquest servidor executa el dimoni Redis, on s'emmagatzemen les entrades del llibre de visites i els comptadors de visitants.
Tots els servidors funcionen amb el mateix nucli de processador. La idea és avaluar el màxim rendiment de cada arquitectura. Atès que tots els programes de servidor es posen a prova amb el mateix maquinari, aquesta és una línia de base per a la comparació. La meva configuració de prova consisteix en servidors virtuals llogats a Digital Ocean.
Què estem mesurant?
Podeu mesurar diferents indicadors. Avaluem el rendiment de cada arquitectura en una configuració determinada carregant els servidors amb peticions a diferents nivells de paral·lelisme: la càrrega creix de 20 a 15 usuaris concurrents.
Resultats de la prova
El gràfic següent mostra el rendiment dels servidors en diferents arquitectures a diferents nivells de paral·lelisme. L'eix Y és el nombre de peticions per segon, l'eix X són connexions paral·leles.
A continuació es mostra una taula amb els resultats.
Pel gràfic i la taula es pot veure que per sobre de 8000 peticions simultànies només ens queden dos jugadors: pre-fork i epoll. A mesura que augmenta la càrrega, un servidor basat en enquestes funciona pitjor que un de streaming. L'arquitectura de pre-creació de fils és un competidor digne d'epoll, un testimoni de com de bé el nucli de Linux programa un gran nombre de fils.
Codi font ZeroHTTPd
Codi font ZeroHTTPd aquí. Hi ha un directori separat per a cada arquitectura.
A més de set directoris per a totes les arquitectures, hi ha dos més al directori de nivell superior: públic i plantilles. El primer conté el fitxer index.html i la imatge de la primera captura de pantalla. Podeu posar-hi altres fitxers i carpetes, i ZeroHTTPd hauria de servir aquests fitxers estàtics sense cap problema. Si el camí del navegador coincideix amb el de la carpeta pública, ZeroHTTPd cerca el fitxer index.html en aquest directori. El contingut del llibre de visites es genera de manera dinàmica. Només té una pàgina d'inici i el seu contingut es basa en el fitxer 'templates/guestbook/index.html'. ZeroHTTPd afegeix fàcilment pàgines dinàmiques per a l'extensió. La idea és que els usuaris puguin afegir plantilles a aquest directori i ampliar ZeroHTTPd segons sigui necessari.
Per crear els set servidors, executeu make all des del directori de nivell superior - i totes les compilacions apareixeran en aquest directori. Els fitxers executables cerquen els directoris públics i de plantilles al directori des del qual s'inicien.
API de Linux
No cal que conegueu bé l'API de Linux per entendre la informació d'aquesta sèrie d'articles. Tanmateix, recomano llegir més sobre aquest tema; hi ha molts recursos de referència a Internet. Tot i que tractarem diverses categories d'API de Linux, el nostre enfocament se centrarà principalment en processos, fils, esdeveniments i la pila de xarxa. A més dels llibres i articles sobre l'API de Linux, també recomano llegir mana per a les trucades al sistema i les funcions de biblioteca utilitzades.
Rendiment i escalabilitat
Una nota sobre el rendiment i l'escalabilitat. Teòricament, no hi ha cap connexió entre ells. Pots tenir un servei web que funcioni molt bé, amb un temps de resposta d'uns quants mil·lisegons, però no escala gens. De la mateixa manera, pot haver-hi una aplicació web amb un rendiment baix que triga uns segons a respondre, però s'escala en desenes per gestionar desenes de milers d'usuaris concurrents. Tanmateix, la combinació d'alt rendiment i escalabilitat és una combinació molt potent. Les aplicacions d'alt rendiment generalment utilitzen els recursos amb moderació i, per tant, serveixen de manera eficient a més usuaris concurrents al servidor, reduint els costos.
Tasques de CPU i E/S
Finalment, en informàtica sempre hi ha dos tipus de tasques possibles: per E/S i CPU. Rebre sol·licituds a través d'Internet (E/S de xarxa), servir fitxers (E/S de xarxa i de disc), comunicar-se amb la base de dades (E/S de xarxa i de disc) són totes activitats d'E/S. Algunes consultes de bases de dades poden ser una mica intensives en CPU (ordenació, mitjana d'un milió de resultats, etc.). La majoria de les aplicacions web estan limitades pel màxim d'E/S possible i el processador rarament s'utilitza a plena capacitat. Quan veieu que alguna tasca d'E/S utilitza molta CPU, és probable que sigui un signe d'una arquitectura deficient de l'aplicació. Això pot significar que els recursos de la CPU es malgasten en la gestió de processos i el canvi de context, i això no és del tot útil. Si feu alguna cosa com el processament d'imatges, la conversió de fitxers d'àudio o l'aprenentatge automàtic, l'aplicació requereix recursos de CPU potents. Però per a la majoria d'aplicacions aquest no és el cas.
Més informació sobre les arquitectures de servidors