Linux-verkkosovellusten suorituskyky. Johdanto

Web-sovelluksia käytetään nyt kaikkialla, ja kaikista siirtoprotokollista HTTP vie leijonanosan. Tutkiessaan verkkosovelluskehityksen vivahteita useimmat ihmiset kiinnittävät hyvin vähän huomiota käyttöjärjestelmään, jossa nämä sovellukset todella toimivat. Kehityksen (Dev) ja toiminnan (Ops) erottaminen vain pahensi tilannetta. Mutta DevOps-kulttuurin nousun myötä kehittäjät ovat vastuussa sovellusten suorittamisesta pilvessä, joten heidän on erittäin hyödyllistä tutustua käyttöjärjestelmän taustaan ​​perusteellisesti. Tämä on erityisen hyödyllistä, jos yrität ottaa käyttöön järjestelmää tuhansia tai kymmeniä tuhansia samanaikaisia ​​yhteyksiä varten.

Verkkopalveluiden rajoitukset ovat hyvin samanlaisia ​​kuin muissa sovelluksissa. Olipa kyseessä kuormantasaajat tai tietokantapalvelimet, kaikilla näillä sovelluksilla on samanlaisia ​​ongelmia korkean suorituskyvyn ympäristössä. Näiden perusrajoitusten ymmärtäminen ja niiden ylittäminen yleensä auttaa sinua arvioimaan verkkosovellustesi suorituskykyä ja skaalautuvuutta.

Kirjoitan tämän artikkelisarjan vastauksena nuorten kehittäjien kysymyksiin, jotka haluavat tulla hyvin perillä oleviksi järjestelmäarkkitehdeiksi. On mahdotonta ymmärtää selkeästi Linux-sovellusten optimointitekniikoita ilman, että sukeltaa niiden perusasioihin, kuinka ne toimivat käyttöjärjestelmätasolla. Vaikka sovelluksia on monenlaisia, tässä sarjassa haluan tutustua verkkopohjaisiin sovelluksiin työpöytäsovellusten, kuten selaimen tai tekstieditorin, sijaan. Tämä materiaali on tarkoitettu kehittäjille ja arkkitehdeille, jotka haluavat ymmärtää kuinka Linux- tai Unix-ohjelmat toimivat ja miten ne rakennetaan korkean suorituskyvyn saavuttamiseksi.

Linux on palvelinhuone käyttöjärjestelmä, ja useimmiten sovelluksesi toimivat tällä käyttöjärjestelmällä. Vaikka sanon "Linux", suurimman osan ajasta voit turvallisesti olettaa, että tarkoitan kaikkia Unix-tyyppisiä käyttöjärjestelmiä yleisesti. En kuitenkaan ole testannut mukana tulevaa koodia muissa järjestelmissä. Joten jos olet kiinnostunut FreeBSD:stä tai OpenBSD:stä, tulokset voivat vaihdella. Kun yritän jotain Linux-spesifistä, osoitan sen.

Vaikka voit käyttää tätä tietämystä sovelluksen rakentamiseen tyhjästä ja se on täydellisesti optimoitu, on parasta olla tekemättä sitä. Jos kirjoitat uuden verkkopalvelimen C- tai C++-kielellä organisaatiosi yrityssovellukseen, tämä voi olla viimeinen työpäiväsi. Näiden sovellusten rakenteen tunteminen auttaa kuitenkin olemassa olevien ohjelmien valinnassa. Pystyt vertailemaan prosessipohjaisia ​​järjestelmiä säiepohjaisiin järjestelmiin sekä tapahtumapohjaisiin järjestelmiin. Ymmärrät ja ymmärrät, miksi Nginx toimii paremmin kuin Apache httpd, miksi Tornado-pohjainen Python-sovellus voi palvella enemmän käyttäjiä verrattuna Django-pohjaiseen Python-sovellukseen.

ZeroHTTPd: Oppimistyökalu

ZeroHTTPd on web-palvelin, jonka kirjoitin tyhjästä C-kielellä opetusvälineenä. Sillä ei ole ulkoisia riippuvuuksia, mukaan lukien pääsy Redisiin. Suoritamme omia Redis-menettelyjämme. Katso alta lisätietoja.

Vaikka teoriasta voisi keskustella pitkään, ei ole mitään parempaa kuin koodin kirjoittaminen, sen suorittaminen ja kaikkien palvelinarkkitehtuurien vertailu. Tämä on ilmeisin menetelmä. Siksi kirjoitamme yksinkertaisen ZeroHTTPd-verkkopalvelimen jokaisella mallilla: prosessipohjainen, säiepohjainen ja tapahtumapohjainen. Tarkastellaan jokaista näistä palvelimista ja katsotaan kuinka ne toimivat toisiinsa verrattuna. ZeroHTTPd on toteutettu yhdessä C-tiedostossa. Tapahtumapohjainen palvelin sisältää uthash, loistava hash-taulukon toteutus, joka tulee yhteen otsikkotiedostoon. Muissa tapauksissa ei ole riippuvuuksia, jotta projekti ei monimutkaista.

Koodissa on paljon kommentteja, jotka auttavat sinua ymmärtämään. Koska ZeroHTTPd on yksinkertainen verkkopalvelin muutamalla koodirivillä, se on myös minimaalinen kehys verkkokehitykseen. Sen toiminnallisuus on rajallinen, mutta se pystyy palvelemaan staattisia tiedostoja ja hyvin yksinkertaisia ​​"dynaamisia" sivuja. Minun on sanottava, että ZeroHTTPd on hyvä opetella luomaan korkean suorituskyvyn Linux-sovelluksia. Yleisesti ottaen useimmat verkkopalvelut odottavat pyyntöjä, tarkistavat ne ja käsittelevät niitä. Juuri tämän ZeroHTTPd tekee. Tämä on työkalu oppimiseen, ei tuotantoon. Se ei ole hyvä virheiden käsittelyssä, eikä sillä todennäköisesti ole parhaita tietoturvakäytäntöjä (joo, käytin strcpy) tai C-kielen taitavia temppuja, mutta toivottavasti se tekee tehtävänsä hyvin.

Linux-verkkosovellusten suorituskyky. Johdanto
ZeroHTTPd kotisivu. Se voi tulostaa erilaisia ​​tiedostotyyppejä, mukaan lukien kuvat

Vieraskirjahakemus

Nykyaikaiset verkkosovellukset eivät yleensä rajoitu staattisiin tiedostoihin. Heillä on monimutkainen vuorovaikutus erilaisten tietokantojen, välimuistien jne. kanssa. Joten luomme yksinkertaisen verkkosovelluksen nimeltä "Vieraskirja", johon vierailijat jättävät merkintöjä nimillään. Vieraskirja tallentaa aiemmin jätetyt merkinnät. Sivun alareunassa on myös kävijälaskuri.

Linux-verkkosovellusten suorituskyky. Johdanto
Web-sovellus "Vieraskirja" ZeroHTTPd

Vierailijalaskuri ja vieraskirjan merkinnät tallennetaan Redisiin. Rediksen kanssa tapahtuvaan kommunikaatioon on otettu käyttöön omat menettelyt, jotka eivät riipu ulkoisesta kirjastosta. En ole suuri homebrew-koodin käyttöönoton fani, kun on olemassa julkisesti saatavilla olevia ja hyvin testattuja ratkaisuja. Mutta ZeroHTTPd:n tarkoitus on tutkia Linuxin suorituskykyä ja pääsyä ulkoisiin palveluihin, kun taas HTTP-pyyntöjen palveleminen vaikuttaa vakavasti suorituskykyyn. Meidän on valvottava täysin viestintää Rediksen kanssa jokaisessa palvelinarkkitehtuurissamme. Joissakin arkkitehtuureissa käytämme estopuheluita, toisissa tapahtumapohjaisia ​​proseduureja. Ulkoisen Redis-asiakaskirjaston käyttäminen ei tarjoa tätä ohjausta. Lisäksi pieni Redis-asiakasohjelmamme suorittaa vain muutamia toimintoja (avaimen saaminen, asettaminen ja lisääminen; taulukon saaminen ja liittäminen). Lisäksi Redis-protokolla on erittäin tyylikäs ja yksinkertainen. Sitä ei tarvitse edes erikseen opettaa. Jo se tosiasia, että protokolla tekee kaiken työn noin sadassa koodirivissä, osoittaa, kuinka hyvin se on harkittu.

Seuraava kuva näyttää, mitä sovellus tekee, kun asiakas (selain) pyytää /guestbookURL.

Linux-verkkosovellusten suorituskyky. Johdanto
Kuinka vieraskirjasovellus toimii

Kun vieraskirjan sivu on annettava, tiedostojärjestelmälle lähetetään yksi puhelu mallin lukemiseksi muistiin ja kolme verkkopuhelua Redikselle. Mallitiedosto sisältää suurimman osan yllä olevan kuvakaappauksen sivun HTML-sisällöstä. Sisällön dynaamiselle osalle on myös erityisiä paikkamerkkejä: viestit ja kävijälaskuri. Saamme ne Redikseltä, lisäämme ne sivulle ja tarjoamme asiakkaalle valmiin sisällön. Kolmas kutsu Redikselle voidaan välttää, koska Redis palauttaa uuden avaimen arvon, kun sitä lisätään. Palvelimellemme, jolla on asynkroninen tapahtumapohjainen arkkitehtuuri, monet verkkopuhelut ovat kuitenkin hyvä testi oppimistarkoituksiin. Joten hylkäämme kävijämäärän Redis-palautusarvon ja kysymme sitä erillisellä kutsulla.

Palvelinarkkitehtuurit ZeroHTTPd

Rakennamme seitsemän versiota ZeroHTTPd:stä, joissa on samat toiminnot mutta erilaiset arkkitehtuurit:

  • Iteratiivinen
  • Fork-palvelin (yksi aliprosessi per pyyntö)
  • Pre-fork-palvelin (prosessien esihaaroittaminen)
  • Palvelin suoritussäikeillä (yksi säie per pyyntö)
  • Palvelin säiettä edeltävällä luomisella
  • Arkkitehtuuriin perustuva poll()
  • Arkkitehtuuriin perustuva epoll

Mittaamme kunkin arkkitehtuurin suorituskyvyn lataamalla palvelimelle HTTP-pyynnöt. Mutta kun verrataan erittäin rinnakkaisia ​​arkkitehtuureja, kyselyiden määrä kasvaa. Testaamme kolme kertaa ja laskemme keskiarvon.

Testausmenetelmä

Linux-verkkosovellusten suorituskyky. Johdanto
ZeroHTTPd-kuormitustestausasetukset

Testejä suoritettaessa on tärkeää, että kaikki komponentit eivät toimi samalla koneella. Tässä tapauksessa käyttöjärjestelmälle aiheutuu ylimääräisiä aikataulutuskustannuksia, kun komponentit kilpailevat suorittimesta. Jokaisen valitun palvelinarkkitehtuurin käyttöjärjestelmän ylärajan mittaaminen on yksi tämän harjoituksen tärkeimmistä tavoitteista. Muuttujien lisäämisestä tulee haitallista prosessille. Siksi yllä olevan kuvan asetus toimii parhaiten.

Mitä kukin näistä palvelimista tekee?

  • load.unixism.net: Täällä toimimme ab, Apache Benchmark -apuohjelma. Se luo kuormituksen, joka tarvitaan palvelinarkkitehtuurimme testaamiseen.
  • nginx.unixism.net: Joskus haluamme suorittaa useamman kuin yhden palvelinohjelman esiintymän. Tätä varten Nginx-palvelin, jolla on asianmukaiset asetukset, toimii kuormantasaajana, joka tulee kohteesta ab palvelinprosesseihimme.
  • zerohttpd.unixism.net: Täällä käytämme palvelinohjelmiamme seitsemällä eri arkkitehtuurilla, yksi kerrallaan.
  • redis.unixism.net: Tämä palvelin käyttää Redis-daemonia, johon tallennetaan vieraskirjan merkinnät ja vierailijalaskurit.

Kaikki palvelimet toimivat samalla prosessoriytimellä. Ajatuksena on arvioida kunkin arkkitehtuurin maksimaalinen suorituskyky. Koska kaikki palvelinohjelmat testataan samalla laitteistolla, tämä on vertailun lähtökohta. Testikokoonpanoni koostuu Digital Oceanilta vuokratuista virtuaalipalvelimista.

Mitä mittaamme?

Voit mitata erilaisia ​​indikaattoreita. Arvioimme kunkin arkkitehtuurin suorituskyvyn tietyssä kokoonpanossa lataamalla palvelimille pyyntöjä eri rinnakkaisuuden tasoilla: kuormitus kasvaa 20:stä 15 000 samanaikaiseen käyttäjään.

Testitulokset

Seuraava kaavio näyttää palvelimien suorituskyvyn eri arkkitehtuureissa eri rinnakkaisuuden tasoilla. Y-akseli on pyyntöjen määrä sekunnissa, x-akseli rinnakkaisia ​​yhteyksiä.

Linux-verkkosovellusten suorituskyky. Johdanto

Linux-verkkosovellusten suorituskyky. Johdanto

Linux-verkkosovellusten suorituskyky. Johdanto

Alla on taulukko tuloksista.

pyyntöjä sekunnissa

rinnakkaisuus
iteratiivinen
haarukka
esihaarukka
suoratoisto
ennakkosuoratoisto
äänestys
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
laajalle levinneelle
2138

5000
-
laajalle levinneelle
1600
1100
2519
-
2235

8000
-
-
1200
laajalle levinneelle
2451
-
2100

10
-
-
laajalle levinneelle
-
2200
-
2200

11
-
-
-
-
2200
-
2122

12
-
-
-
-
970
-
1958

13
-
-
-
-
730
-
1897

14
-
-
-
-
590
-
1466

15
-
-
-
-
532
-
1281

Kaaviosta ja taulukosta näkyy, että yli 8000 samanaikaista pyyntöä meillä on enää kaksi pelaajaa jäljellä: pre-fork ja epoll. Kun kuormitus kasvaa, kyselyyn perustuva palvelin toimii huonommin kuin suoratoistopalvelin. Säikeen luomista edeltävä arkkitehtuuri on arvokas kilpailija epollille, osoitus siitä, kuinka hyvin Linux-ydin ajoittaa suuria määriä säikeitä.

ZeroHTTPd-lähdekoodi

ZeroHTTPd-lähdekoodi täällä. Jokaiselle arkkitehtuurille on oma hakemisto.

ZeroHTTPd │ ├── 01_iterative │ ├── main.c ├── 02_haarukka │ ├── main.c ├── 03_preforking ─. 04_ pujotus │ ├── main.c ├── 05_prethreading │ ├── main.c ├── 06_poll │ ├── main.c ├── 07_epoll │ └─── Julkinen tiedosto.c ──├─── ├── hakemisto .html │ └── tux png └── mallit └── vieraskirja └── index.html

Seitsemän kaikkien arkkitehtuurien hakemiston lisäksi huipputason hakemistossa on kaksi muuta: julkinen ja mallit. Ensimmäinen sisältää index.html-tiedoston ja kuvan ensimmäisestä kuvakaappauksesta. Voit laittaa sinne muita tiedostoja ja kansioita, ja ZeroHTTPd:n pitäisi palvella nuo staattiset tiedostot ilman ongelmia. Jos selaimen polku vastaa julkisen kansion polkua, ZeroHTTPd etsii index.html-tiedostoa tästä hakemistosta. Vieraskirjan sisältö luodaan dynaamisesti. Sillä on vain kotisivu, ja sen sisältö perustuu tiedostoon 'templates/guestbook/index.html'. ZeroHTTPd lisää helposti dynaamisia sivuja laajennuksia varten. Ajatuksena on, että käyttäjät voivat lisätä malleja tähän hakemistoon ja laajentaa ZeroHTTPd:tä tarpeen mukaan.

Suorita rakentaaksesi kaikki seitsemän palvelinta make all ylätason hakemistosta - ja kaikki koontiversiot näkyvät tässä hakemistossa. Suoritettavat tiedostot etsivät julkisia ja mallihakemistoja hakemistosta, josta ne käynnistetään.

Linux API

Sinun ei tarvitse olla hyvin perehtynyt Linux-sovellusliittymään ymmärtääksesi tämän artikkelisarjan tietoja. Suosittelen kuitenkin lukemaan lisää tästä aiheesta, sillä Internetissä on paljon viiteresursseja. Vaikka käsittelemmekin useita Linux-sovellusliittymien luokkia, keskitymme ensisijaisesti prosesseihin, säikeisiin, tapahtumiin ja verkkopinoon. Linux-sovellusliittymää koskevien kirjojen ja artikkeleiden lisäksi suosittelen myös manan lukemista järjestelmäkutsuille ja käytetyille kirjastotoiminnoille.

Suorituskyky ja skaalautuvuus

Yksi huomautus suorituskyvystä ja skaalautumisesta. Teoriassa niiden välillä ei ole yhteyttä. Sinulla voi olla erittäin hyvin toimiva verkkopalvelu, jonka vasteaika on muutaman millisekunnin, mutta se ei skaalaudu ollenkaan. Samoin voi olla huonosti toimiva verkkosovellus, jonka vastaaminen kestää muutaman sekunnin, mutta se skaalautuu kymmenillä kymmenillä tuhansilla samanaikaisilla käyttäjillä. Korkean suorituskyvyn ja skaalautuvuuden yhdistelmä on kuitenkin erittäin tehokas yhdistelmä. Suorituskykyiset sovellukset käyttävät yleensä resursseja säästeliäästi ja palvelevat siten tehokkaasti useampia samanaikaisia ​​käyttäjiä palvelimella, mikä vähentää kustannuksia.

CPU- ja I/O-tehtävät

Lopuksi laskennassa on aina kaksi mahdollista tehtävätyyppiä: I/O:lle ja CPU:lle. Pyyntöjen vastaanottaminen Internetin kautta (verkko-I/O), tiedostojen palveleminen (verkko- ja levy-I/O), kommunikointi tietokannan kanssa (verkko ja levy-I/O) ovat kaikki I/O-toimintoja. Jotkut tietokantakyselyt voivat olla hieman prosessoriintensiivisiä (lajittelu, miljoonan tuloksen keskiarvo jne.). Useimpia verkkosovelluksia rajoittaa suurin mahdollinen I/O, ja prosessoria käytetään harvoin täydellä kapasiteetilla. Kun huomaat, että jokin I/O-tehtävä käyttää paljon suoritinta, se on todennäköisesti merkki huonosta sovellusarkkitehtuurista. Tämä voi tarkoittaa, että suorittimen resursseja tuhlataan prosessien hallintaan ja kontekstin vaihtamiseen - ja tämä ei ole täysin hyödyllistä. Jos teet jotain, kuten kuvankäsittelyä, äänitiedostojen muuntamista tai koneoppimista, sovellus vaatii tehokkaita suoritinresursseja. Mutta useimmissa sovelluksissa näin ei ole.

Lisätietoja palvelinarkkitehtuureista

  1. Osa I: Iteratiivinen arkkitehtuuri
  2. Osa II. Haarukkapalvelimet
  3. Osa III. Pre-fork-palvelimet
  4. Osa IV. Palvelimet, joissa on suoritussäikeitä
  5. Osa V. Esisäikeiset palvelimet
  6. Osa VI. Pol-pohjainen arkkitehtuuri
  7. Osa VII. epoll-pohjainen arkkitehtuuri

Lähde: will.com

Lisää kommentti