Ytelse for Linux-nettverksapplikasjoner. Introduksjon

Webapplikasjoner brukes nå overalt, og blant alle transportprotokoller opptar HTTP brorparten. Når de studerer nyansene i utvikling av nettapplikasjoner, legger de fleste svært liten vekt på operativsystemet der disse applikasjonene faktisk kjører. Separasjonen av utvikling (Dev) og operasjoner (Ops) gjorde bare situasjonen verre. Men med fremveksten av DevOps-kulturen, blir utviklere ansvarlige for å kjøre applikasjonene sine i skyen, så det er veldig nyttig for dem å bli grundig kjent med bakenden av operativsystemet. Dette er spesielt nyttig hvis du prøver å distribuere et system for tusenvis eller titusenvis av samtidige tilkoblinger.

Begrensningene i webtjenester er veldig like de i andre applikasjoner. Enten det er lastbalansere eller databaseservere, har alle disse applikasjonene lignende problemer i et miljø med høy ytelse. Å forstå disse grunnleggende begrensningene og hvordan du kan overvinne dem generelt vil hjelpe deg med å evaluere ytelsen og skalerbarheten til nettapplikasjonene dine.

Jeg skriver denne serien med artikler som svar på spørsmål fra unge utviklere som ønsker å bli velinformerte systemarkitekter. Det er umulig å tydelig forstå teknikker for Linux-applikasjonsoptimalisering uten å dykke ned i det grunnleggende om hvordan de fungerer på operativsystemnivå. Selv om det finnes mange typer applikasjoner, ønsker jeg i denne serien å utforske nettbaserte applikasjoner i stedet for skrivebordsapplikasjoner som en nettleser eller tekstredigerer. Dette materialet er ment for utviklere og arkitekter som ønsker å forstå hvordan Linux- eller Unix-programmer fungerer og hvordan de kan struktureres for høy ytelse.

Linux er serverrom operativsystem, og som oftest kjører applikasjonene dine på dette operativsystemet. Selv om jeg sier "Linux", kan du som oftest trygt anta at jeg mener alle Unix-lignende operativsystemer generelt. Jeg har imidlertid ikke testet den medfølgende koden på andre systemer. Så hvis du er interessert i FreeBSD eller OpenBSD, kan resultatene dine variere. Når jeg prøver noe Linux-spesifikt, påpeker jeg det.

Selv om du kan bruke denne kunnskapen til å bygge en app fra bunnen av, og den vil være perfekt optimalisert, er det best å ikke gjøre det. Hvis du skriver en ny webserver i C eller C++ for organisasjonens forretningsapplikasjon, kan dette være din siste dag på jobben. Men å kjenne strukturen til disse applikasjonene vil hjelpe deg med å velge eksisterende programmer. Du vil kunne sammenligne prosessbaserte systemer med trådbaserte systemer så vel som hendelsesbaserte. Du vil forstå og sette pris på hvorfor Nginx presterer bedre enn Apache httpd, hvorfor en Tornado-basert Python-applikasjon kan tjene flere brukere sammenlignet med en Django-basert Python-applikasjon.

ZeroHTTPd: Læringsverktøy

NullHTTPd er en webserver som jeg skrev fra bunnen av i C som et undervisningsverktøy. Den har ingen eksterne avhengigheter, inkludert tilgang til Redis. Vi kjører våre egne Redis-prosedyrer. Se nedenfor for flere detaljer.

Selv om vi kunne diskutere teori i lengden, er det ingenting bedre enn å skrive kode, kjøre den og sammenligne alle serverarkitekturer med hverandre. Dette er den mest åpenbare metoden. Derfor vil vi skrive en enkel ZeroHTTPd-nettserver ved å bruke hver modell: prosessbasert, trådbasert og hendelsesbasert. La oss sjekke ut hver av disse serverne og se hvordan de presterer sammenlignet med hverandre. ZeroHTTPd er implementert i en enkelt C-fil. Den hendelsesbaserte serveren inkluderer uthash, en flott hashtabellimplementering som kommer i en enkelt overskriftsfil. I andre tilfeller er det ingen avhengigheter, for ikke å komplisere prosjektet.

Det er mange kommentarer i koden for å hjelpe deg å forstå. Siden ZeroHTTPd er en enkel webserver på noen få linjer med kode, er ZeroHTTPd også et minimalt rammeverk for webutvikling. Den har begrenset funksjonalitet, men er i stand til å betjene statiske filer og veldig enkle "dynamiske" sider. Jeg må si at ZeroHTTPd er bra for å lære å lage høyytelses Linux-applikasjoner. I det store og hele venter de fleste nettjenester på forespørsler, sjekker dem og behandler dem. Dette er nøyaktig hva ZeroHTTPd vil gjøre. Dette er et verktøy for læring, ikke produksjon. Den er ikke god til å håndtere feil og vil neppe skryte av beste sikkerhetspraksis (å ja, jeg brukte strcpy) eller de smarte triksene til C-språket. Men jeg håper det gjør jobben sin bra.

Ytelse for Linux-nettverksapplikasjoner. Introduksjon
ZeroHTTPd hjemmeside. Den kan sende ut forskjellige filtyper, inkludert bilder

Søknad om gjestebok

Moderne nettapplikasjoner er vanligvis ikke begrenset til statiske filer. De har komplekse interaksjoner med ulike databaser, cacher osv. Så vi vil lage en enkel nettapplikasjon kalt "Gjestebok" hvor besøkende legger igjen oppføringer under navnet sitt. Gjesteboken lagrer oppføringer som er igjen tidligere. Det er også en besøksteller nederst på siden.

Ytelse for Linux-nettverksapplikasjoner. Introduksjon
Nettapplikasjon "Gjestebok" ZeroHTTPd

Besøkstelleren og gjestebokoppføringer lagres i Redis. For kommunikasjon med Redis implementeres egne prosedyrer, de er ikke avhengige av det eksterne biblioteket. Jeg er ikke en stor fan av å rulle ut hjemmebryggekode når det er offentlig tilgjengelige og veltestede løsninger. Men formålet med ZeroHTTPd er å studere Linux-ytelse og tilgang til eksterne tjenester, mens servering av HTTP-forespørsler har en alvorlig ytelsespåvirkning. Vi må ha full kontroll over kommunikasjonen med Redis i hver av våre serverarkitekturer. I noen arkitekturer bruker vi blokkeringsanrop, i andre bruker vi hendelsesbaserte prosedyrer. Bruk av et eksternt Redis-klientbibliotek vil ikke gi denne kontrollen. I tillegg utfører vår lille Redis-klient bare noen få funksjoner (hente, stille inn og øke en nøkkel; hente og legge til en array). I tillegg er Redis-protokollen ekstremt elegant og enkel. Du trenger ikke engang å undervise det spesielt. Selve det faktum at protokollen gjør alt arbeidet på rundt hundre linjer med kode viser hvor gjennomtenkt den er.

Følgende figur viser hva applikasjonen gjør når klienten (nettleseren) ber om /guestbookURL.

Ytelse for Linux-nettverksapplikasjoner. Introduksjon
Slik fungerer gjesteboksøknaden

Når en gjestebokside må utgis, er det ett anrop til filsystemet for å lese malen inn i minnet og tre nettverksanrop til Redis. Malfilen inneholder det meste av HTML-innholdet for siden i skjermbildet ovenfor. Det er også spesielle plassholdere for den dynamiske delen av innholdet: innlegg og besøksteller. Vi mottar dem fra Redis, setter dem inn på siden og gir kunden fullt utformet innhold. Det tredje kallet til Redis kan unngås fordi Redis returnerer den nye nøkkelverdien når den økes. Men for vår server, som har en asynkron hendelsesbasert arkitektur, er mange nettverksanrop en god test for læringsformål. Så vi forkaster Redis-returverdien for antall besøkende og spør etter den med et eget anrop.

Serverarkitekturer ZeroHTTPd

Vi bygger syv versjoner av ZeroHTTPd med samme funksjonalitet, men forskjellige arkitekturer:

  • Iterativ
  • Gaffelserver (en underordnet prosess per forespørsel)
  • Pre-fork server (pre-forking av prosesser)
  • Server med utførelsestråder (én tråd per forespørsel)
  • Server med pre-thread-oppretting
  • Arkitektur basert poll()
  • Arkitektur basert epoll

Vi måler ytelsen til hver arkitektur ved å laste serveren med HTTP-forespørsler. Men når man sammenligner svært parallelle arkitekturer, øker antallet spørringer. Vi tester tre ganger og regner ut gjennomsnittet.

Testmetodikk

Ytelse for Linux-nettverksapplikasjoner. Introduksjon
ZeroHTTPd belastningstestoppsett

Det er viktig at når du kjører tester, kjører ikke alle komponentene på samme maskin. I dette tilfellet pådrar operativsystemet seg ekstra planleggingskostnader ettersom komponenter konkurrerer om CPU. Å måle driftssystemets overhead for hver av de valgte serverarkitekturene er et av de viktigste målene med denne øvelsen. Å legge til flere variabler vil være skadelig for prosessen. Derfor fungerer innstillingen på bildet over best.

Hva gjør hver av disse serverne?

  • load.unixism.net: Det er her vi kjører ab, Apache Benchmark-verktøy. Den genererer belastningen som trengs for å teste serverarkitekturene våre.
  • nginx.unixism.net: Noen ganger ønsker vi å kjøre mer enn én forekomst av et serverprogram. For å gjøre dette fungerer Nginx-serveren med de riktige innstillingene som en lastbalanser som kommer fra ab til våre serverprosesser.
  • zerohttpd.unixism.net: Her kjører vi serverprogrammene våre på syv forskjellige arkitekturer, én om gangen.
  • redis.unixism.net: Denne serveren kjører Redis-demonen, hvor gjestebokoppføringer og besøkstellere lagres.

Alle servere kjører på samme prosessorkjerne. Ideen er å evaluere den maksimale ytelsen til hver arkitektur. Siden alle serverprogrammer er testet på samme maskinvare, er dette en baseline for sammenligning. Testoppsettet mitt består av virtuelle servere leid fra Digital Ocean.

Hva måler vi?

Du kan måle forskjellige indikatorer. Vi evaluerer ytelsen til hver arkitektur i en gitt konfigurasjon ved å laste inn serverne med forespørsler på forskjellige nivåer av parallellitet: belastningen vokser fra 20 til 15 000 samtidige brukere.

Testresultater

Følgende diagram viser ytelsen til servere på forskjellige arkitekturer på forskjellige nivåer av parallellitet. Y-aksen er antall forespørsler per sekund, x-aksen er parallelle forbindelser.

Ytelse for Linux-nettverksapplikasjoner. Introduksjon

Ytelse for Linux-nettverksapplikasjoner. Introduksjon

Ytelse for Linux-nettverksapplikasjoner. Introduksjon

Nedenfor er en tabell med resultatene.

forespørsler per sekund

parallellitet
iterativ
gaffel
forgaffel
streaming
forhåndsstrømming
avstemning
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 000
-
-
stor 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 det sees at over 8000 samtidige forespørsler har vi bare to spillere igjen: pre-fork og epoll. Etter hvert som belastningen øker, presterer en meningsmåling-basert server dårligere enn en streaming. Tråd-pre-opprettingsarkitekturen er en verdig konkurrent til epoll, et bevis på hvor godt Linux-kjernen planlegger et stort antall tråder.

ZeroHTTPd kildekode

ZeroHTTPd kildekode her. Det er en egen katalog for hver arkitektur.

ZeroHTTPd │ ├── 01_iterativ │ ├── main.c ├── 02_forking │ ├── main.c ├── 03_preforking ─────││ _ ​​gjenger │ ├── hoved.c ├── 04_prethreading │ ├── main.c ├── 05_poll │ ├── main.c ├── 06_epoll │ └── ─── ─e ├ ├── indeks .html │ └── tux . png └── maler └── gjestebok └── index.html

I tillegg til syv kataloger for alle arkitekturer, er det to til i katalogen på toppnivå: offentlige og maler. Den første inneholder filen index.html og bildet fra det første skjermbildet. Du kan legge andre filer og mapper der, og ZeroHTTPd skal tjene opp de statiske filene uten problemer. Hvis banen i nettleseren samsvarer med banen i den offentlige mappen, ser ZeroHTTPd etter index.html-filen i denne katalogen. Innholdet til gjesteboken genereres dynamisk. Den har bare en hjemmeside, og innholdet er basert på filen 'templates/guestbook/index.html'. ZeroHTTPd legger enkelt til dynamiske sider for utvidelse. Tanken er at brukere kan legge til maler i denne katalogen og utvide ZeroHTTPd etter behov.

For å bygge alle de syv serverne, kjør make all fra katalogen på øverste nivå - og alle bygg vil vises i denne katalogen. Kjørbare filer ser etter de offentlige katalogene og malkatalogene i katalogen de er lansert fra.

Linux API

Du trenger ikke å være godt kjent med Linux API for å forstå informasjonen i denne artikkelserien. Jeg anbefaler imidlertid å lese mer om dette emnet; det er mange referanseressurser på Internett. Selv om vi vil berøre flere kategorier av Linux APIer, vil vårt fokus primært være på prosesser, tråder, hendelser og nettverksstakken. I tillegg til bøker og artikler om Linux API, anbefaler jeg også å lese mana for systemanrop og bibliotekfunksjoner som brukes.

Ytelse og skalerbarhet

En merknad om ytelse og skalerbarhet. Teoretisk er det ingen sammenheng mellom dem. Du kan ha en webtjeneste som fungerer veldig bra, med en responstid på noen millisekunder, men den skalerer ikke i det hele tatt. På samme måte kan det være en nettapplikasjon med dårlig ytelse som tar noen sekunder å svare, men den skaleres med titalls for å håndtere titusenvis av samtidige brukere. Kombinasjonen av høy ytelse og skalerbarhet er imidlertid en veldig kraftig kombinasjon. Høyytelsesapplikasjoner bruker vanligvis ressurser sparsomt og betjener dermed mer samtidige brukere på serveren effektivt, noe som reduserer kostnadene.

CPU og I/O oppgaver

Til slutt, i databehandling er det alltid to mulige typer oppgaver: for I/O og CPU. Å motta forespørsler over Internett (nettverk I/O), servere filer (nettverk og disk I/O), kommunisere med databasen (nettverk og disk I/O) er alle I/O-aktiviteter. Noen databasespørringer kan være litt CPU-intensive (sortering, gjennomsnittlig en million resultater osv.). De fleste webapplikasjoner er begrenset av maksimalt mulig I/O, og prosessoren brukes sjelden med full kapasitet. Når du ser at noen I/O-oppgaver bruker mye CPU, er det mest sannsynlig et tegn på dårlig applikasjonsarkitektur. Dette kan bety at CPU-ressurser kastes bort på prosesshåndtering og kontekstbytte – og dette er ikke helt nyttig. Hvis du gjør noe som bildebehandling, lydfilkonvertering eller maskinlæring, krever applikasjonen kraftige CPU-ressurser. Men for de fleste applikasjoner er dette ikke tilfelle.

Lær mer om serverarkitekturer

  1. Del I: Iterativ arkitektur
  2. Del II. Gaffelservere
  3. Del III. Pre-fork servere
  4. Del IV. Servere med utførelsestråder
  5. Del V. Forhåndsgjengede servere
  6. Del VI. Pol-basert arkitektur
  7. Del VII. epoll-basert arkitektur

Kilde: www.habr.com

Legg til en kommentar