Prestaties van netwerkapplicaties in Linux. Inleiding

Webapplicaties worden tegenwoordig overal gebruikt, en onder alle transportprotocollen neemt HTTP een belangrijke plaats in. Bij het bestuderen van de nuances van webapplicatieontwikkeling, besteden de meeste mensen echter heel weinig aandacht aan het besturingssysteem waarop deze applicaties daadwerkelijk draaien. De scheiding tussen ontwikkeling (Dev) en operatie (Ops) heeft de situatie alleen maar verergerd. Maar met de opkomst van de DevOps-cultuur beginnen ontwikkelaars verantwoordelijkheden te nemen voor het draaien van hun applicaties in de cloud, waardoor het voor hen zeer nuttig is om zich grondig te verdiepen in de backend van het besturingssysteem. Dit is vooral handig als je een systeem probeert op te zetten voor duizenden of tienduizenden gelijktijdige verbindingen.

Beperkingen in webservices zijn heel vergelijkbaar met beperkingen in andere applicaties. Of het nu gaat om load balancers of database servers, al deze applicaties hebben soortgelijke problemen in een omgeving met hoge prestaties. Begrip van deze fundamentele beperkingen en manieren om ze in het algemeen te overwinnen, zal helpen bij het beoordelen van de prestaties en schaalbaarheid van je webapplicaties.

Ik schrijf deze serie artikelen als reactie op de vragen van jonge ontwikkelaars die goed geïnformeerde systeemsarchitecten willen worden. Het is onmogelijk om de optimalisatiemethoden voor Linux-applicaties goed te begrijpen zonder de basisprincipes te doorgronden van hoe ze werken op het niveau van het besturingssysteem. Hoewel er veel soorten applicaties zijn, wil ik in deze cyclus netwerkafflicaties onderzoeken, en niet desktopapplicaties zoals browsers of tekstverwerkers. Dit materiaal is gericht op ontwikkelaars en architecten die willen begrijpen hoe Linux- of Unix-programma's functioneren en hoe ze gestructureerd kunnen worden voor hoge prestaties.

Linux is een server- besturingssysteem, en vaak draaien je applicaties op dit OS. Hoewel ik "Linux" zeg, kun je in de meeste gevallen met een gerust hart aannemen dat alle Unix-achtige besturingssystemen in het algemeen worden bedoeld. Desondanks heb ik de bijbehorende code niet op andere systemen getest. Dus als je geïnteresseerd bent in FreeBSD of OpenBSD, kan het resultaat anders zijn. Wanneer ik iets specifieks voor Linux probeer, geef ik dat aan.

Hoewel je de opgedane kennis kunt gebruiken om een applicatie vanuit het niets te creëren, wat geweldig geoptimaliseerd kan zijn, is het beter om dat niet te doen. Als je een nieuwe webserver in C of C++ schrijft voor de zakelijke applicatie van je organisatie, kan het wel eens je laatste werkdag zijn. Echter, een begrip van de structuur van deze applicaties helpt bij het kiezen van reeds bestaande programma's. Je kunt systemen op basis van processen vergelijken met systemen op basis van threads en ook met die op basis van gebeurtenissen. Je zult begrijpen en waarderen waarom Nginx beter presteert dan Apache httpd, en waarom een Python-applicatie gebaseerd op Tornado meer gebruikers kan bedienen dan een Python-applicatie op basis van Django.

ZeroHTTPd: leermiddel

ZeroHTTPd — een webserver die ik vanaf nul heb geschreven in C als een leermiddel. Het heeft geen externe afhankelijkheden, ook geen toegang tot Redis. We draaien onze eigen Redis-processen. Zie hieronder voor meer informatie.

Hoewel we lang over de theorie zouden kunnen discussiëren, is er niets beter dan het schrijven van code, deze uit te voeren en alle serverarchitecturen met elkaar te vergelijken. Dit is de meest visuele methode. Daarom gaan we een eenvoudige webserver ZeroHTTPd schrijven, waarbij we elk model toepassen: op basis van processen, threads en gebeurtenissen. We zullen elke server testen en kijken hoe ze zich verhouden tot elkaar. ZeroHTTPd is geïmplementeerd in één C-bestand. De event-based server bevat uthash, een geweldige implementatie van een hash-tabel die wordt geleverd in één headerbestand. Verder zijn er geen afhankelijkheden, zodat het project niet wordt complicate.

De code bevat veel comments om te helpen begrijpen. Als een eenvoudige webserver in een paar regels code, vormt ZeroHTTPd ook een minimaal framework voor webontwikkeling. Het heeft beperkte functionaliteit, maar kan statische bestanden en zeer eenvoudige 'dynamische' pagina's serveren. Ik moet zeggen dat ZeroHTTPd goed geschikt is voor het leren hoe je hoogpresterende Linux-applicaties kunt maken. Over het algemeen wachten de meeste webservices op verzoeken, controleren ze en verwerken ze. Dat is precies wat ZeroHTTPd zal doen. Het is een leermiddel, geen productie-oplossing. Het is niet sterk in foutafhandeling en zal waarschijnlijk niet de beste beveiligingspraktijken kunnen bieden (oh ja, ik heb gebruik gemaakt van strcpy) of with cryptic tricks of the C language. But I hope it will perform its task well.

Prestaties van netwerkapplicaties in Linux. Inleiding
De startpagina van ZeroHTTPd. Het kan verschillende soorten bestanden afleveren, waaronder afbeeldingen.

Gastenboek applicatie.

Moderne webapplicaties zijn doorgaans niet beperkt tot statische bestanden. Ze hebben complexe interacties met verschillende databases, caches, enz. Daarom gaan we een eenvoudige webapplicatie maken genaamd 'Gastenboek', waar bezoekers berichten achterlaten onder hun naam. In het gastenboek worden eerder achtergelaten berichten opgeslagen. Er is ook een bezoekersaantal onderaan de pagina.

Prestaties van netwerkapplicaties in Linux. Inleiding
Webapplicatie 'Gastenboek' van ZeroHTTPd.

Het bezoekersaantal en de gastenboekberichten worden opgeslagen in Redis. Voor de communicatie met Redis zijn eigen procedures geïmplementeerd, die onafhankelijk zijn van externe bibliotheken. Ik ben geen grote fan van het uitrollen van zelfgemaakte code wanneer er publiek beschikbare en goed geteste oplossingen zijn. Maar het doel van ZeroHTTPd is om de prestaties van Linux en de toegang tot externe diensten te bestuderen, terwijl het afhandelen van HTTP-verzoeken een aanzienlijke invloed heeft op de prestaties. We moeten de communicatie met Redis in al onze serverarchitecturen volledig kunnen controleren. In de ene architectuur gebruiken we блокирующие aanroepen, in andere event-gebaseerde procedures. Het gebruik van een externe Redis-clientbibliotheek biedt deze controle niet. Bovendien voert onze kleine Redis-client slechts enkele functies uit (het ophalen, instellen en verhogen van een sleutel; het ophalen en toevoegen aan een array). Daarbij is het Redis-protocol uitzonderlijk elegant en eenvoudig. Het hoeft zelfs niet speciaal geleerd te worden. Het feit dat het hele werk door het protocol ongeveer in honderd regels code is uitgevoerd, toont aan hoe goed het is doordacht.

In de volgende afbeelding worden de acties van de applicatie getoond wanneer de client (browser) een aanvraag doet. /guestbookURL.

Prestaties van netwerkapplicaties in Linux. Inleiding
Werking van de gastenboek applicatie.

Wanneer een pagina van het gastenboek moet worden weergegeven, gebeurt er één aanroep naar het bestandssysteem om de sjabloon in het geheugen te lezen en drie netwerkaanroepen naar Redis. Het sjabloonbestand bevat het meeste HTML-inhoud voor de pagina op de screenshot bovenaan. Er zijn ook speciale plaatsaanduidingen voor het dynamische gedeelte van de inhoud: berichten en het bezoekersaantal. We halen deze uit Redis, voegen ze op de pagina in en geven de klant de volledig gevormde inhoud. De derde aanroep naar Redis kan worden vermeden, aangezien Redis een nieuwe waarde van de sleutel retourneert bij verhoging. Voor onze server met een op gebeurtenissen gebaseerde asynchrone architectuur zijn meerdere netwerkaanroepen echter een goede test voor educatieve doeleinden. Daarom negeren we de geretourneerde waarde van Redis over het aantal bezoekers en vragen we deze met een aparte aanroep aan.

Serverarchitecturen ZeroHTTPd

We bouwen zeven versies van ZeroHTTPd met dezelfde functionaliteit, maar verschillende architecturen:

  • Iteratief
  • Fork-server (één subprocess per verzoek)
  • Prefork server (vooraf forked processen)
  • Server met uitvoerthreads (één thread per verzoek)
  • Server met vooraf gecreëerde threads
  • Architectuur op basis van poll()
  • Architectuur op basis van epoll

We meten de prestaties van elke architectuur door de server te belasten met HTTP-verzoeken. Maar bij het vergelijken van architecturen met een hoge mate van parallelisme neemt het aantal verzoeken toe. We testen drie keer en berekenen het gemiddelde.

Testmethodologie

Prestaties van netwerkapplicaties in Linux. Inleiding
Installatie voor stress-testen van ZeroHTTPd

Het is belangrijk dat tijdens het testen alle componenten niet op één machine draaien. In dit geval heeft het besturingssysteem extra overhead voor scheduling, omdat de componenten concurreren om de CPU. Het meten van de overhead van het besturingssysteem met elk van de gekozen serverarchitecturen is een van de belangrijkste doelstellingen van deze oefening. Het toevoegen van meer variabelen zou schadelijk zijn voor het proces. Daarom werkt de configuratie op de afbeelding hierboven het beste.

Wat doet elk van deze servers?

  • load.unixism.net: hier draaien we ab, de Apache Benchmark-tool. Deze genereert de vereiste belasting om onze serverarchitecturen te testen.
  • nginx.unixism.net: Soms willen we meer dan één instantie van een serverprogramma uitvoeren. Hiervoor fungeert de Nginx-server met de juiste instellingen als een load balancer voor ab onze serverprocessen.
  • zerohttpd.unixism.net: hier draaien we onze serverprogramma's op zeven verschillende architecturen, één tegelijk.
  • redis.unixism.net: op deze server draait de Redis-daemon, waar de gegevens van het gastenboek en de bezoekerscounter worden opgeslagen.

Alle servers draaien op één CPU-kern. Het idee is om de maximale prestaties van elke architectuur te evalueren. Aangezien alle serverprogramma's op dezelfde hardware worden getest, is dit de basislijn voor hun vergelijking. Mijn testopstelling bestaat uit virtuele servers die zijn gehuurd van Digital Ocean.

Wat meten we?

Er kunnen verschillende statistieken worden gemeten. We evalueren de prestaties van elke architectuur in deze configuratie door de servers te belasten met aanvragen op verschillende niveaus van parallelisme: de belasting stijgt van 20 tot 15.000 gelijktijdige gebruikers.

Testresultaten

In de volgende diagram wordt de prestaties van de servers op verschillende architecturen bij verschillende niveaus van parallelisme weergegeven. Op de y-as staat het aantal aanvragen per seconde, op de x-as de parallelle verbindingen.

Prestaties van netwerkapplicaties in Linux. Inleiding

Prestaties van netwerkapplicaties in Linux. Inleiding

Prestaties van netwerkapplicaties in Linux. Inleiding

Hieronder staat een tabel met resultaten.

aanvragen per seconde

parallelisme
iteratief
fork
vooraf fork
draad
vooraf draad
poll
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
grote spreiding
2138

5000
–
grote spreiding
1600
1100
2519
–
2235

8000
–
–
1200
grote spreiding
2451
–
2100

10 000
–
–
grote spreiding
–
2200
–
2200

11 000
–
–
–
–
2200
–
2122

12 000
–
–
–
–
970
–
1958

13 000
–
–
–
–
730
–
1897

14 000
–
–
–
–
590
–
1466

15 000
–
–
–
–
532
–
1281

Uit de grafiek en tabel blijkt dat bij meer dan 8000 gelijktijdige aanvragen er alleen twee spelers overblijven: vooraf fork en epoll. Naarmate de belasting toeneemt, presteert de op polling gebaseerde server slechter dan de draad-architectuur. De architectuur met vooraf aangemaakte draden vormt een serieuze concurrent voor epoll: dit getuigt van hoe goed de Linux-kernel een groot aantal draden plant.

Broncode ZeroHTTPd

Broncode ZeroHTTPd hier. Voor elke architectuur is er een aparte map.

ZeroHTTPd
│
├── 01_iterative
│   ├── main.c
├── 02_forking
│   ├── main.c
├── 03_preforking
│   ├── main.c
├── 04_threading
│   ├── main.c
├── 05_prethreading
│   ├── main.c
├── 06_poll
│   ├── main.c
├── 07_epoll
│    └── main.c
├── Makefile
├── public
│   ├── index.html
│   └── tux.png
└── templates
    └── guestbook
        └── index.html

Naast de zeven mappen voor alle architecturen, zijn er nog twee in de bovenliggende directory: public en templates. In de eerste bevindt zich het bestand index.html en een afbeelding van de eerste schermafbeelding. Hier kunnen andere bestanden en mappen worden geplaatst, en ZeroHTTPd zou deze statische bestanden probleemloos moeten kunnen serveren. Als het pad in de browser overeenkomt met het pad in de public-map, zoekt ZeroHTTPd in deze directory het bestand index.html. De inhoud voor het gastenboek wordt dynamisch gegenereerd. Het heeft alleen de startpagina, en de inhoud is gebaseerd op het bestand ‘templates/guestbook/index.html’. In ZeroHTTPd kunnen eenvoudig dynamische pagina's worden toegevoegd ter uitbreiding. Het idee is dat gebruikers sjablonen in deze directory kunnen toevoegen en ZeroHTTPd naar behoefte kunnen uitbreiden.

Om alle zeven servers te bouwen, voert u make all uit de bovenliggende directory - en alle builds verschijnen in deze directory. De uitvoerbare bestanden zoeken de directories public en templates in de directory van waaruit ze worden uitgevoerd.

Linux API

Om de informatie in deze artikelenreeks te begrijpen, is het niet nodig om een expert te zijn in de Linux API. Ik raad echter aan om meer te lezen over dit onderwerp, er zijn veel bronnen online. Hoewel we enkele categorieën van de Linux API zullen behandelen, zal onze aandacht voornamelijk gericht zijn op processen, threads, gebeurtenissen en de netwerkstack. Naast boeken en artikelen over de Linux API, raad ik ook aan om de man-pagina’s van systeemaanroepen en gebruikte bibliotheekfuncties te lezen.

Prestaties en schaalbaarheid

Een opmerking over prestaties en schaalbaarheid. Theoretisch is er geen enkele relatie tussen hen. U kunt een webservice hebben die heel goed presteert, met responstijden van enkele milliseconden, maar die helemaal niet schaalbaar is. Evenzo kan er een slecht presterende webapplicatie zijn die enkele seconden nodig heeft voor een reactie, maar die schaalbaar is tot tientallen om tienduizenden gelijktijdige gebruikers te verwerken. Desalniettemin is de combinatie van hoge prestaties en schaalbaarheid een zeer krachtige combinatie. Hoogpresterende applicaties maken over het algemeen zuinig gebruik van middelen en kunnen zo efficiënt meer gelijktijdige gebruikers op de server bedienen, waardoor de kosten worden verlaagd.

CPU- en I/O-taken

Uiteindelijk zijn er altijd twee mogelijke typen taken in berekeningen: voor I/O en CPU. Het ontvangen van verzoeken via het internet (netwerk I/O), het bedienen van bestanden (netwerk- en schijf-I/O), communicatie met een database (netwerk- en schijf-I/O) — dit zijn allemaal I/O-acties. Sommige databaseverzoeken kunnen de CPU een beetje belasten (zoals sorteren, het berekenen van het gemiddelde van een miljoen resultaten, enz.). De meeste webapplicaties zijn beperkt in de maximaal mogelijke I/O, terwijl de processor zelden op volle capaciteit wordt gebruikt. Wanneer je ziet dat er veel CPU wordt gebruikt voor een bepaalde I/O-taak, is dat waarschijnlijk een teken van een slechte applicatiearchitectuur. Dit kan betekenen dat de CPU-resources worden verspild aan procesbeheer en contextwisseling - en dat is niet echt nuttig. Als je iets doet zoals beeldverwerking, audiobestandconversie of machine learning, dan vereist de applicatie krachtige CPU-resources. Maar voor de meeste applicaties is dat niet het geval.

Meer over serverarchitecturen

  1. Deel I. Iteratieve architectuur
  2. Deel II. Fork-servers
  3. Deel III. Pre-fork servers
  4. Deel IV. Servers met uitvoeringsthreads
  5. Deel V. Servers met voorafgaande threadcreatie
  6. Deel VI. Architectuur gebaseerd op poll
  7. Deel VII. Architectuur gebaseerd op epoll

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers 🔥 Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster