Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion

Webapplikationer bruges nu overalt, og blandt alle transportprotokoller udgÞr HTTP stÞrstedelen. NÄr man studerer detaljer i webapplikationsudvikling, bliver operativsystemet, hvor disse applikationer faktisk kÞrer, ofte overset. Opdelingen mellem udvikling (Dev) og drift (Ops) har kun forvÊrret situationen. Men med udbredelsen af DevOps-kulturen begynder udviklerne at pÄtage sig ansvaret for at kÞre deres applikationer i skyen, sÄ det er meget nyttigt for dem at blive grundigt bekendt med backend'en i 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 ligner meget dem i andre applikationer. Uanset om det er belastningsbalance eller databaser, har alle disse applikationer lignende problemer i hÞjtydende miljÞer. At forstÄ disse grundlÊggende begrÊnsninger og mÄder at overvinde dem pÄ vil generelt tillade dig at vurdere ydeevnen og skalerbarheden af dine webapplikationer.

Jeg skriver denne serie artikler som svar pÄ spÞrgsmÄl fra unge udviklere, der Þnsker at blive velbevandrede systemarkitekter. Det er umuligt at forstÄ metoderne til optimering af Linux-applikationer uden at dykke ned i det grundlÊggende, og hvordan de fungerer pÄ operativsystemniveau. Selvom der findes mange typer applikationer, vil jeg i denne cyklus undersÞge netvÊrksapplikationer og ikke desktop-applikationer som browsere eller tekstbehandlere. Dette materiale er rettet mod udviklere og arkitekter, der Þnsker at forstÄ, hvordan Linux- eller Unix-programmer fungerer, og hvordan man strukturerer dem til hÞj ydeevne.

Linux er et server- operativsystem, og oftest kÞrer dine applikationer netop pÄ dette OS. Selvom jeg siger "Linux", kan du stÞrstedelen af tiden med sikkerhed antage, at der menes alle Unix-lignende operativsystemer generelt. Jeg har dog ikke testet den medfÞlgende kode pÄ andre systemer. SÄ hvis du er interesseret i FreeBSD eller OpenBSD, kan resultaterne variere. NÄr jeg prÞver noget, der er specifikt for Linux, angiver jeg det.

Selvom du kan bruge den viden, du fÄr, til at bygge en applikation fra bunden, som vil vÊre fremragende optimeret, er det bedst ikke at gÞre det. Hvis du skriver en ny webserver i C eller C++ til din organisations forretningsapplikation, kan det vÊre din sidste dag pÄ jobbet. Men at have kendskab til strukturen af disse applikationer vil hjÊlpe dig med at vÊlge mellem allerede eksisterende programmer. Du vil kunne sammenligne systemer baseret pÄ processer med systemer baseret pÄ trÄde samt systemer baseret pÄ begivenheder. Du vil forstÄ og vÊrdsÊtte, hvorfor Nginx fungerer bedre end Apache httpd, og hvorfor en Python-applikation baseret pÄ Tornado kan betjene flere brugere sammenlignet med en Python-applikation baseret pÄ Django.

ZeroHTTPd: lĂŠringsvĂŠrktĂžj

ZeroHTTPd — en webserver, som jeg skrev fra bunden i C som et léringsvérktþj. Den har ingen eksterne afhéngigheder, herunder adgang til Redis. Vi kþrer vores egne Redis-processer. Lés mere nedenfor.

Selvom vi kunne diskutere teorien lÊnge, er der ikke noget bedre end at skrive noget kode, kÞre det og sammenligne alle serverarkitekturer. Det er den mest visuelle metode. Derfor vil vi skrive en simpel webserver, ZeroHTTPd, ved at anvende hver model: baseret pÄ processer, trÄde og begivenheder. Vi vil teste hver af disse servere og se, hvordan de fungerer i forhold til hinanden. ZeroHTTPd er implementeret i en enkelt C-fil. Serveren baseret pÄ begivenheder inkluderer uthash, en fremragende implementering af en hash-tabel, der leveres i én header-fil. I Þvrige tilfÊlde er der ingen afhÊngigheder for ikke at komplicere projektet.

Der er mange kommentarer i koden for at hjÊlpe med forstÄelsen. Som en simpel webserver med et par linjer kode fungerer ZeroHTTPd ogsÄ som et minimalt framework for webudvikling. Den har begrÊnset funktionalitet, men den kan levere statiske filer og meget enkle 'dynamiske' sider. Jeg mÄ sige, at ZeroHTTPd er godt til at lÊre, hvordan man skaber hÞjtydende Linux-applikationer. Generelt set venter de fleste webtjenester pÄ forespÞrgsler, kontrollerer dem og behandler dem. Det er prÊcis, hvad ZeroHTTPd vil gÞre. Det er et lÊringsvÊrktÞj, ikke til produktion. Den er ikke stÊrk i fejlbehandling og vil nÊppe prale af de bedste sikkerhedspraksisser (Äh ja, jeg brugte strcpy) eller med komplicerede tricks i C-sproget. Men jeg hÄber, det vil klare sin opgave godt.

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion
Hjemmesiden for ZeroHTTPd. Den kan server forskellige filtyper, inklusive billeder.

GĂŠstebogsapplikation

Moderne webapplikationer er normalt ikke begrÊnset til statiske filer. De har komplekse interaktioner med forskellige databaser, caches osv. Derfor vil vi skabe en simpel webapplikation kaldet "GÊstebog", hvor besÞgende kan efterlade indlÊg under deres navne. I gÊstebogen gemmes tidligere efterladte indlÊg. Der er ogsÄ en tÊller for besÞgende nederst pÄ siden.

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion
Webapplikationen "GĂŠstebog" ZeroHTTPd

TÊlleren for besÞgende og indlÊg i gÊstebogen gemmes i Redis. Der er implementeret egne procedurer til kommunikation med Redis, som ikke er afhÊngige af eksterne biblioteker. Jeg er ikke stor fan af at rulle egen kode ud, nÄr der er offentligt tilgÊngelige og veldokumenterede lÞsninger. Men mÄlet med ZeroHTTPd er at undersÞge ydeevnen i Linux og adgangen til eksterne tjenester, mens behandling af HTTP-anmodninger har en alvorlig indvirkning pÄ ydeevnen. Vi skal have fuld kontrol over kommunikationen med Redis i hver af vores serverarkitekturer. I en arkitektur bruger vi blokkerende kald, i andre er der procedurer baseret pÄ hÊndelser. Brug af et eksternt Redis-klientbibliotek vil ikke give den kontrol. Derudover udfÞrer vores lille Redis-klient kun fÄ funktioner (hentning, indstilling og inkrementering af nÞgler; hentning og tilfÞjelse til arrays). Desuden er Redis-protokollen sÊrdeles elegant og enkel. Man behÞver endda ikke at lÊre det specifikt. Faktisk viser det, at hele arbejdet udfÞres af protokollen i cirka hundrede linjer kode, hvor godt designet det er.

Den fÞlgende illustration viser handlingerne i applikationen, nÄr klienten (browseren) anmoder /guestbookURL.

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion
Mekanismen bag gĂŠstebogsapplikationen

NÄr der skal vises en side fra gÊstebogen, foretages der et kald til filsystemet for at lÊse skabelonen ind i hukommelsen og tre netvÊrkskald til Redis. Skabelonfilen indeholder det meste af HTML-indholdet til siden pÄ skÊrmbilledet ovenfor. Der er ogsÄ specielle pladsholdere til den dynamiske del af indholdet: indlÊg og besÞgstÊller. Vi henter dem fra Redis, indsÊtter dem pÄ siden og leverer det fuldt udformede indhold til klienten. Det tredje kald til Redis kan undgÄs, da Redis returnerer den nye vÊrdi af nÞglen ved opdatering. Men for vores server med asynkron event-baseret arkitektur er mange netvÊrkskald en god Þvelse med hensyn til lÊring. Derfor forkaster vi den returnerede vÊrdi fra Redis om antallet af besÞgende og anmoder om den med et separat kald.

Serverarkitekturer ZeroHTTPd

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

  • Iterativ
  • Fork server (Ă©n dataproces pr. anmodning)
  • Pre-fork server (forudgĂ„ende forking af processer)
  • TrĂ„d-server (Ă©n trĂ„d pr. anmodning)
  • Server med forudoprettede trĂ„de
  • Arkitektur baseret pĂ„ poll()
  • Arkitektur baseret pĂ„ epoll

Vi mÄler ydeevnen af hver arkitektur ved at belaste serveren med HTTP-anmodninger. Men nÄr man sammenligner arkitekturer med hÞj parallelisme, Þges antallet af anmodninger. Vi tester tre gange og beregner gennemsnittet.

Testmetodologi

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion
OpsĂŠtning til belastningstestning af ZeroHTTPd

Det er vigtigt, at alle komponenter ikke kÞrer pÄ én maskine under testene. I dette tilfÊlde pÄdrager OS ekstra omkostninger til planlÊgning, da komponenterne konkurrerer om CPU'en. At mÄle de operationelle systemomkostninger med hver af de valgte serverarkitekturer er et af de vigtigste mÄl med denne Þvelse. At tilfÞje flere variabler vil vÊre skadeligt for processen. Derfor fungerer opsÊtningen pÄ billedet ovenfor bedst.

Hvad gĂžr hver af disse servere

  • load.unixism.net: her kĂžrer vi ab, Apache Benchmark-vĂŠrktĂžjet. Det genererer den belastning, der er nĂždvendig for at teste vores serverarkitekturer.
  • nginx.unixism.net: Nogle gange Ăžnsker vi at kĂžre mere end Ă©n instans af serverprogrammet. For dette fungerer Nginx-serveren med de passende indstillinger som en belastningsfordeler for indkommende ab til vores serverprocesser.
  • zerohttpd.unixism.net: Her kĂžrer vi vores serverprogrammer pĂ„ syv forskellige arkitekturer, en ad gangen.
  • redis.unixism.net: PĂ„ denne server kĂžrer Redis-dĂŠmonen, hvor gĂŠstebogsindlĂŠg og besĂžgsregistreringer opbevares.

Alle servere kÞrer pÄ en enkelt CPU-kerne. Ideen er at vurdere den maksimale ydeevne for hver af arkitekturerne. Da alle serverprogrammer testes pÄ det samme udstyr, er dette en basislinje for deres sammenligning. Min testopsÊtning bestÄr af virtuelle servere lejet fra Digital Ocean.

Hvad mÄler vi?

Forskellige metrikker kan mÄles. Vi vurderer ydeevnen for hver arkitektur i denne konfiguration ved at belaste serverne med anmodninger pÄ forskellige niveauer af parallelisme: belastningen stiger fra 20 til 15.000 samtidige brugere.

Test Results

I det fÞlgende diagram vises servernes ydeevne pÄ forskellige arkitekturer ved forskellige niveauer af parallelisme. PÄ y-aksen er antallet af anmodninger pr. sekund, og pÄ x-aksen er de parallelle forbindelser.

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion

Ydelsen af netvĂŠrksapplikationer i Linux. Introduktion

Nedenfor er en tabel med resultaterne.

anmodninger pr. sekund

parallelisme
iterativ
en fork
pre-fork
trÄdet
pre-threaded
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
stort spredning
2138

5000
–
stort spredning
1600
1100
2519
–
2235

8000
–
–
1200
stort spredning
2451
–
2100

10 000
–
–
stort spredning
–
2200
–
2200

11 000
–
–
–
–
2200
–
2122

12 000
–
–
–
–
970
–
1958

13 000
–
–
–
–
730
–
1897

14 000
–
–
–
–
590
–
1466

15 000
–
–
–
–
532
–
1281

Fra grafen og tabellen kan vi se, at over 8000 samtidige anmodninger har vi kun to spillere tilbage: pre-fork og epoll. EfterhÄnden som belastningen stiger, prÊsterer serveren baseret pÄ poll dÄrligere end den trÄdede. Arkitekturen med forudlavede trÄde udgÞr en vÊrdig konkurrence mod epoll: dette viser, hvor godt Linux-kernen planlÊgger et stort antal trÄde.

Kildekoden til ZeroHTTPd

Kildekoden til ZeroHTTPd her. For hver arkitektur er der et separat katalog.

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

Udover de syv kataloger til alle arkitekturer er der endnu to i rodkatalogen: public og templates. I den fĂžrste ligger filen index.html og billedet fra det fĂžrste skĂŠrmbillede. Du kan placere andre filer og mapper der, og ZeroHTTPd skal uden problemer kunne levere disse statiske filer. Hvis stien i browseren svarer til stien i mappen public, sĂ„ sĂžger ZeroHTTPd i denne katalog efter filen index.html. Indholdet til gĂŠstebogen genereres dynamisk. Den har kun en forside, og dens indhold er baseret pĂ„ filen ‘templates/guestbook/index.html’. I ZeroHTTPd er det nemt at tilfĂžje dynamiske sider for at udvide funktionaliteten. Ideen er, at brugerne kan tilfĂžje skabeloner i denne katalog og udvide ZeroHTTPd efter behov.

For at bygge alle syv servere, kĂžr make all fra rodkatalogen - og alle builds vil dukke op i denne katalog. De eksekverbare filer sĂžger efter katalogerne public og templates i den katalog, de kĂžres fra.

Linux API

For at forstÄ informationen i denne artikelcyklus er det ikke nÞdvendigt at have en dyb forstÄelse af Linux API. Jeg anbefaler dog at lÊse mere om emnet, da der findes mange ressourcer online. Selvom vi vil berÞre flere kategorier af Linux API, vil vores fokus primÊrt vÊre pÄ processer, trÄde, begivenheder og netvÊrksstakken. Udover bÞger og artikler om Linux API anbefaler jeg ogsÄ at lÊse manualerne for systemopkald og de biblioteksfunktioner, der anvendes.

Ydelse og skalerbarhed

En bemÊrkning om ydelse og skalerbarhed. Teoretisk set er der ingen forbindelse mellem dem. Du kan have en webservice, der fungerer rigtig godt, med svartider pÄ fÄ millisekunder, men som ikke skalerer overhovedet. PÄ samme mÄde kan der vÊre en webapplikation, der fungerer dÄrligt og tager flere sekunder at svare, men som skalerer til at hÄndtere titusinder af samtidige brugere. Ikke desto mindre er kombinationen af hÞj ydelse og skalerbarhed en meget kraftfuld kombination. HÞjtydende applikationer bruger generelt ressourcer sparsomt og kan derfor effektivt betjene flere samtidige brugere pÄ serveren, hvilket reducerer omkostningerne.

CPU- og I/O-opgaver

Endelig er der altid to mulige typer opgaver i beregninger: I/O og CPU. Modtagelse af anmodninger over internettet (netvĂŠrksind- og uddata), administration af filer (netvĂŠrks- og diskind- og uddata), kommunikation med databaser (netvĂŠrks- og diskind- og uddata) – alt dette er I/O-handlinger. Nogle anmodninger til databasen kan belaste CPU'en lidt (sortering, beregning af gennemsnittet af en million resultater osv.). De fleste webapplikationer er begrĂŠnset af den maksimalt mulige I/O, mens CPU'en sjĂŠldent anvendes fuldt ud. NĂ„r du ser, at en eller anden I/O-opgave bruger meget CPU, er det sandsynligvis et tegn pĂ„ dĂ„rlig applikationsarkitektur. Det kan betyde, at CPU-ressourcer bruges pĂ„ processtyring og kontekstskift – og det er ikke sĂŠrlig nyttigt. Hvis du laver noget som billedbehandling, konvertering af lydfiler eller maskinlĂŠring, sĂ„ krĂŠver applikationen kraftige CPU-ressourcer. Men for de fleste applikationer er det ikke tilfĂŠldet.

Mere om serverarkitekturer

  1. Del I. Iterativ arkitektur
  2. Del II. Fork-servere
  3. Del III. Pre-fork servere
  4. Del IV. Servere med udfÞrelsestrÄde
  5. Del V. Servere med prÊkompilerede trÄde
  6. Del VI. Poll-baseret arkitektur
  7. Del VII. Epoll-baseret arkitektur

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster