Linux-netværksapplikationsydelse. Introduktion

Webapplikationer bruges nu overalt, og blandt alle transportprotokoller optager HTTP brorparten. Når de studerer nuancerne i udvikling af webapplikationer, er de fleste mennesker meget lidt opmærksomme på det operativsystem, hvor disse applikationer rent faktisk kører. Adskillelsen af ​​udvikling (Dev) og operationer (Ops) gjorde kun situationen værre. Men med fremkomsten af ​​DevOps-kulturen bliver udviklere ansvarlige for at køre deres applikationer i skyen, så det er meget nyttigt for dem at blive grundigt fortrolige med backend af operativsystemet. Dette er især nyttigt, hvis du forsøger at implementere et system til tusindvis eller titusindvis af samtidige forbindelser.

Begrænsningerne i webtjenester er meget lig dem i andre applikationer. Uanset om det er load balancere eller databaseservere, har alle disse applikationer lignende problemer i et højtydende miljø. At forstå disse grundlæggende begrænsninger og hvordan man overvinder dem generelt vil hjælpe dig med at evaluere ydeevnen og skalerbarheden af ​​dine webapplikationer.

Jeg skriver denne serie af artikler som svar på spørgsmål fra unge udviklere, der ønsker at blive velinformerede systemarkitekter. Det er umuligt klart at forstå Linux-applikationsoptimeringsteknikker uden at dykke ned i det grundlæggende i, hvordan de fungerer på operativsystemniveau. Selvom der er mange typer applikationer, vil jeg i denne serie gerne udforske webbaserede applikationer i stedet for desktopapplikationer såsom en browser eller teksteditor. Dette materiale er beregnet til udviklere og arkitekter, der ønsker at forstå, hvordan Linux- eller Unix-programmer fungerer, og hvordan de struktureres til høj ydeevne.

Linux er serverrum operativsystem, og oftest kører dine applikationer på dette OS. Selvom jeg siger "Linux", kan man for det meste roligt gå ud fra, at jeg mener alle Unix-lignende styresystemer generelt. Jeg har dog ikke testet den medfølgende kode på andre systemer. Så hvis du er interesseret i FreeBSD eller OpenBSD, kan dine resultater variere. Når jeg prøver noget Linux-specifikt, påpeger jeg det.

Selvom du kan bruge denne viden til at bygge en app fra bunden, og den vil være perfekt optimeret, er det bedst ikke at gøre det. Hvis du skriver en ny webserver i C eller C++ til din organisations forretningsapplikation, kan dette være din sidste dag på jobbet. Men at kende strukturen af ​​disse applikationer vil hjælpe med at vælge eksisterende programmer. Du vil være i stand til at sammenligne procesbaserede systemer med trådbaserede systemer såvel som begivenhedsbaserede. Du vil forstå og værdsætte, hvorfor Nginx yder bedre end Apache httpd, hvorfor en Tornado-baseret Python-applikation kan tjene flere brugere sammenlignet med en Django-baseret Python-applikation.

ZeroHTTPd: Læringsværktøj

NulHTTPd er en webserver, som jeg skrev fra bunden i C som undervisningsværktøj. Den har ingen eksterne afhængigheder, herunder adgang til Redis. Vi kører vores egne Redis-procedurer. Se nedenfor for flere detaljer.

Selvom vi kunne diskutere teori indgående, er der intet bedre end at skrive kode, køre den og sammenligne alle serverarkitekturer med hinanden. Dette er den mest oplagte metode. Derfor vil vi skrive en simpel ZeroHTTPd-webserver ved hjælp af hver model: procesbaseret, trådbaseret og hændelsesbaseret. Lad os tjekke hver af disse servere og se, hvordan de klarer sig sammenlignet med hinanden. ZeroHTTPd er implementeret i en enkelt C-fil. Den hændelsesbaserede server inkluderer uthash, en fantastisk hash-tabelimplementering, der kommer i en enkelt header-fil. I andre tilfælde er der ingen afhængigheder, for ikke at komplicere projektet.

Der er en masse kommentarer i koden for at hjælpe dig med at forstå. Da ZeroHTTPd er en simpel webserver på et par linjer kode, er ZeroHTTPd også en minimal ramme til webudvikling. Den har begrænset funktionalitet, men er i stand til at betjene statiske filer og meget simple "dynamiske" sider. Jeg må sige, at ZeroHTTPd er god til at lære at skabe højtydende Linux-applikationer. I det store og hele venter de fleste webtjenester på anmodninger, tjekker dem og behandler dem. Det er præcis, hvad ZeroHTTPd vil gøre. Dette er et værktøj til læring, ikke produktion. Den er ikke god til fejlhåndtering og vil sandsynligvis ikke prale af bedste sikkerhedspraksis (åh ja, jeg brugte strcpy) eller C-sprogets smarte tricks. Men jeg håber, det gør sit arbejde godt.

Linux-netværksapplikationsydelse. Introduktion
ZeroHTTPd hjemmeside. Det kan udskrive forskellige filtyper inklusive billeder

Ansøgning om gæstebog

Moderne webapplikationer er normalt ikke begrænset til statiske filer. De har komplekse interaktioner med forskellige databaser, caches osv. Så vi vil lave en simpel webapplikation kaldet "Gæstebog", hvor besøgende efterlader indtastninger under deres navn. Gæstebogen gemmer tidligere indgange. Der er også en besøgstæller nederst på siden.

Linux-netværksapplikationsydelse. Introduktion
Webapplikation "Gæstebog" ZeroHTTPd

Besøgstælleren og gæstebogsposter gemmes i Redis. For kommunikation med Redis implementeres egne procedurer, de afhænger ikke af det eksterne bibliotek. Jeg er ikke en stor fan af at udrulle homebrew-kode, når der er offentligt tilgængelige og gennemtestede løsninger. Men målet med ZeroHTTPd er at studere Linux-ydeevne og adgang til eksterne tjenester, mens servering af HTTP-anmodninger har en alvorlig indvirkning på ydeevnen. Vi skal fuldt ud kontrollere kommunikationen med Redis i hver af vores serverarkitekturer. I nogle arkitekturer bruger vi blokerende opkald, i andre bruger vi hændelsesbaserede procedurer. Brug af et eksternt Redis-klientbibliotek giver ikke denne kontrol. Derudover udfører vores lille Redis-klient kun nogle få funktioner (hente, indstille og øge en nøgle; hente og tilføje til et array). Derudover er Redis-protokollen ekstremt elegant og enkel. Du behøver ikke engang at undervise det specielt. Selve det faktum, at protokollen udfører alt arbejdet i omkring hundrede linjer kode viser, hvor gennemtænkt den er.

Følgende figur viser, hvad applikationen gør, når klienten (browseren) anmoder /guestbookURL.

Linux-netværksapplikationsydelse. Introduktion
Sådan fungerer gæstebogsansøgningen

Når en gæstebogsside skal udsendes, er der et opkald til filsystemet for at læse skabelonen ind i hukommelsen og tre netværksopkald til Redis. Skabelonfilen indeholder det meste af HTML-indholdet for siden i skærmbilledet ovenfor. Der er også særlige pladsholdere for den dynamiske del af indholdet: indlæg og besøgstæller. Vi modtager dem fra Redis, indsætter dem på siden og giver kunden fuldt udformet indhold. Det tredje kald til Redis kan undgås, fordi Redis returnerer den nye nøgleværdi, når den øges. Men for vores server, som har en asynkron begivenhedsbaseret arkitektur, er mange netværksopkald en god test til læringsformål. Så vi kasserer Redis-returværdien for antallet af besøgende og forespørger det med et separat opkald.

Serverarkitekturer ZeroHTTPd

Vi bygger syv versioner af ZeroHTTPd med samme funktionalitet, men forskellige arkitekturer:

  • Iterativ
  • Fork server (en underordnet proces pr. anmodning)
  • Pre-fork server (pre-forking af processer)
  • Server med udførelsestråde (én tråd pr. anmodning)
  • Server med præ-tråd oprettelse
  • Arkitektur baseret poll()
  • Arkitektur baseret epoll

Vi måler hver arkitekturs ydeevne ved at indlæse serveren med HTTP-anmodninger. Men når man sammenligner meget parallelle arkitekturer, stiger antallet af forespørgsler. Vi tester tre gange og beregner gennemsnittet.

Testmetode

Linux-netværksapplikationsydelse. Introduktion
Opsætning af nulHTTPd-belastningstest

Det er vigtigt, at når der køres test, kører alle komponenter ikke på samme maskine. I dette tilfælde medfører operativsystemet yderligere planlægningsomkostninger, da komponenter konkurrerer om CPU. Måling af operativsystemets overhead for hver af de valgte serverarkitekturer er et af de vigtigste mål med denne øvelse. Tilføjelse af flere variabler vil blive skadeligt for processen. Derfor fungerer opsætningen på billedet ovenfor bedst.

Hvad gør hver af disse servere?

  • load.unixism.net: Det er her, vi kører ab, Apache Benchmark-værktøj. Det genererer den nødvendige belastning for at teste vores serverarkitekturer.
  • nginx.unixism.net: Nogle gange ønsker vi at køre mere end én forekomst af et serverprogram. For at gøre dette fungerer Nginx-serveren med de relevante indstillinger som en belastningsbalancer, der kommer fra ab til vores serverprocesser.
  • zerohttpd.unixism.net: Her kører vi vores serverprogrammer på syv forskellige arkitekturer, én ad gangen.
  • redis.unixism.net: Denne server kører Redis-dæmonen, hvor gæstebogsindlæg og besøgstællere gemmes.

Alle servere kører på den samme processorkerne. Ideen er at evaluere den maksimale ydeevne af hver arkitektur. Da alle serverprogrammer er testet på den samme hardware, er dette en baseline til sammenligning. Mit testopsætning består af virtuelle servere lejet fra Digital Ocean.

Hvad måler vi?

Du kan måle forskellige indikatorer. Vi evaluerer ydeevnen af ​​hver arkitektur i denne konfiguration ved at indlæse serverne med anmodninger på forskellige niveauer af parallelitet: belastningen vokser fra 20 til 15 samtidige brugere.

Testresultater

Følgende diagram viser ydeevnen af ​​servere på forskellige arkitekturer på forskellige niveauer af parallelitet. Y-aksen er antallet af anmodninger pr. sekund, x-aksen er parallelle forbindelser.

Linux-netværksapplikationsydelse. Introduktion

Linux-netværksapplikationsydelse. Introduktion

Linux-netværksapplikationsydelse. Introduktion

Nedenfor er en tabel med resultaterne.

anmodninger i sekundet

parallelisme
iterativ
gaffel
forgaffel
streaming
pre-streaming
afstemning
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
stor spredning
2138

5000
-
stor spredning
1600
1100
2519
-
2235

8000
-
-
1200
stor spredning
2451
-
2100

10
-
-
stor spredning
-
2200
-
2200

11
-
-
-
-
2200
-
2122

12
-
-
-
-
970
-
1958

13
-
-
-
-
730
-
1897

14
-
-
-
-
590
-
1466

15
-
-
-
-
532
-
1281

Fra grafen og tabellen kan det ses, at over 8000 samtidige anmodninger har vi kun to spillere tilbage: pre-fork og epoll. Efterhånden som belastningen stiger, klarer en meningsmåling-baseret server sig dårligere end en streaming. Tråd-før-oprettelse-arkitekturen er en værdig konkurrent til epoll, et vidnesbyrd om, hvor godt Linux-kernen planlægger et stort antal tråde.

ZeroHTTPd kildekode

ZeroHTTPd kildekode her. Der er en separat mappe for hver arkitektur.

NulHTTPd
│
├── 01_iterativ
│ ├── hoved.c
├──02_forking
│ ├── hoved.c
├── 03_preforking
│ ├── hoved.c
├── 04_threading
│ ├── hoved.c
├── 05_fortrådning
│ ├── hoved.c
├── 06_afstemning
│ ├── hoved.c
├── 07_epoll
│ └── hoved.c
├── Makefile
├── offentlig
│ ├── index.html
│ └── tux.png
└── skabeloner
    └── gæstebog
        └── index.html

Ud over syv mapper til alle arkitekturer er der yderligere to i biblioteket på øverste niveau: offentlige og skabeloner. Den første indeholder filen index.html og billedet fra det første skærmbillede. Du kan lægge andre filer og mapper der, og ZeroHTTPd skulle tjene disse statiske filer uden problemer. Hvis stien i browseren matcher stien i den offentlige mappe, så leder ZeroHTTPd efter filen index.html i denne mappe. Indholdet til gæstebogen genereres dynamisk. Den har kun en startside, og dens indhold er baseret på filen 'templates/guestbook/index.html'. ZeroHTTPd tilføjer nemt dynamiske sider til udvidelse. Ideen er, at brugere kan tilføje skabeloner til denne mappe og udvide ZeroHTTPd efter behov.

Kør for at bygge alle syv servere make all fra biblioteket på øverste niveau - og alle builds vises i denne mappe. Eksekverbare filer leder efter de offentlige mapper og skabeloner i den mappe, hvorfra de startes.

Linux API

Du behøver ikke at være velbevandret i Linux API for at forstå oplysningerne i denne artikelserie. Jeg anbefaler dog at læse mere om dette emne; der er mange referenceressourcer på internettet. Selvom vi vil berøre flere kategorier af Linux API'er, vil vores fokus primært være på processer, tråde, begivenheder og netværksstakken. Ud over bøger og artikler om Linux API anbefaler jeg også at læse mana for systemkald og anvendte biblioteksfunktioner.

Ydeevne og skalerbarhed

En bemærkning om ydeevne og skalerbarhed. Teoretisk er der ingen sammenhæng mellem dem. Du kan have en webservice, der fungerer meget godt, med en responstid på et par millisekunder, men den skalerer slet ikke. Ligeledes kan der være en dårligt ydende webapplikation, der tager et par sekunder at reagere, men den skaleres med tiere for at håndtere titusindvis af samtidige brugere. Kombinationen af ​​høj ydeevne og skalerbarhed er dog en meget kraftfuld kombination. Højtydende applikationer bruger generelt ressourcer sparsomt og betjener dermed effektivt flere samtidige brugere på serveren, hvilket reducerer omkostningerne.

CPU og I/O opgaver

Endelig er der i computeren altid to mulige typer opgaver: for I/O og CPU. Modtagelse af anmodninger over internettet (netværks-I/O), servering af filer (netværk og disk-I/O) og kommunikation med databasen (netværk og disk-I/O) er alle I/O-aktiviteter. Nogle databaseforespørgsler kan være en smule CPU-intensive (sortering, gennemsnit af en million resultater osv.). De fleste webapplikationer er begrænset af den maksimalt mulige I/O, og processoren bruges sjældent med fuld kapacitet. Når du ser, at nogle I/O-opgaver bruger meget CPU, er det højst sandsynligt et tegn på dårlig applikationsarkitektur. Det kan betyde, at CPU-ressourcer spildes på processtyring og kontekstskifte – og det er ikke helt brugbart. Hvis du laver noget som billedbehandling, lydfilkonvertering eller maskinlæring, kræver applikationen kraftige CPU-ressourcer. Men for de fleste applikationer er dette ikke tilfældet.

Lær mere om serverarkitekturer

  1. Del I: Iterativ arkitektur
  2. Del II. Gaffelservere
  3. Del III. Pre-fork servere
  4. Del IV. Servere med udførelsestråde
  5. Del V. Pre-threaded servere
  6. Del VI. Pol-baseret arkitektur
  7. Del VII. epoll-baseret arkitektur

Kilde: www.habr.com

Tilføj en kommentar