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.

Rendiment d'aplicacions de xarxa Linux. Introducció
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.

Rendiment d'aplicacions de xarxa Linux. Introducció
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.

Rendiment d'aplicacions de xarxa Linux. Introducció
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

Rendiment d'aplicacions de xarxa Linux. Introducció
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.

Rendiment d'aplicacions de xarxa Linux. Introducció

Rendiment d'aplicacions de xarxa Linux. Introducció

Rendiment d'aplicacions de xarxa Linux. Introducció

A continuació es mostra una taula amb els resultats.

peticions per segon

paral·lelisme
iteratiu
forquilla
pre-forquilla
streaming
pre-streaming
enquesta
epoll

20
7
112
2100
1800
2250
1900
2050

50
7
190
2200
1700
2200
2000
2000

100
7
245
2200
1700
2200
2150
2100

200
7
330
2300
1750
2300
2200
2100

300
-
380
2200
1800
2400
2250
2150

400
-
410
2200
1750
2600
2000
2000

500
-
440
2300
1850
2700
1900
2212

600
-
460
2400
1800
2500
1700
2519

700
-
460
2400
1600
2490
1550
2607

800
-
460
2400
1600
2540
1400
2553

900
-
460
2300
1600
2472
1200
2567

1000
-
475
2300
1700
2485
1150
2439

1500
-
490
2400
1550
2620
900
2479

2000
-
350
2400
1400
2396
550
2200

2500
-
280
2100
1300
2453
490
2262

3000
-
280
1900
1250
2502
gran difusió
2138

5000
-
gran difusió
1600
1100
2519
-
2235

8000
-
-
1200
gran difusió
2451
-
2100

10
-
-
gran difusió
-
2200
-
2200

11
-
-
-
-
2200
-
2122

12
-
-
-
-
970
-
1958

13
-
-
-
-
730
-
1897

14
-
-
-
-
590
-
1466

15
-
-
-
-
532
-
1281

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.

ZeroHTTPd │ ├── 01_iteratiu │ ├── main.c ├── 02_forking │ ├── main.c ├─── 03_preforking │────── 04_ roscat │ ├── main.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └── fer públic main.c ───├── ├── índex .html │ └── tux . png └── plantilles └── llibre de visites └── index.html

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

  1. Part I: Arquitectura iterativa
  2. Part II. Servidors de bifurcació
  3. Part III. Servidors pre-fork
  4. Part IV. Servidors amb fils d'execució
  5. Part V. Servidors pre-threaded
  6. Part VI. Arquitectura basada en Pol
  7. Part VII. arquitectura basada en epoll

Font: www.habr.com

Afegeix comentari