Spletne aplikacije se zdaj uporabljajo povsod, med vsemi transportnimi protokoli pa HTTP zavzema levji delež. Pri preučevanju nians razvoja spletnih aplikacij večina ljudi posveča zelo malo pozornosti operacijskemu sistemu, v katerem se te aplikacije dejansko izvajajo. Ločitev razvoja (Dev) in operacij (Ops) je situacijo le še poslabšala. Toda z vzponom kulture DevOps razvijalci postajajo odgovorni za izvajanje svojih aplikacij v oblaku, zato je zanje zelo koristno, da se temeljito seznanijo z zaledjem operacijskega sistema. To je še posebej uporabno, če poskušate razmestiti sistem za več tisoč ali deset tisoč sočasnih povezav.
Omejitve v spletnih storitvah so zelo podobne tistim v drugih aplikacijah. Ne glede na to, ali gre za izravnalnike obremenitve ali strežnike baz podatkov, imajo vse te aplikacije podobne težave v visoko zmogljivem okolju. Razumevanje teh temeljnih omejitev in kako jih na splošno premagati vam bo pomagalo oceniti učinkovitost in razširljivost vaših spletnih aplikacij.
To serijo člankov pišem kot odgovor na vprašanja mladih razvijalcev, ki želijo postati dobro obveščeni sistemski arhitekti. Nemogoče je jasno razumeti tehnike optimizacije aplikacij Linux, ne da bi se poglobili v osnove njihovega delovanja na ravni operacijskega sistema. Čeprav obstaja veliko vrst aplikacij, želim v tej seriji raziskati spletne aplikacije in ne namizne aplikacije, kot sta brskalnik ali urejevalnik besedila. To gradivo je namenjeno razvijalcem in arhitektom, ki želijo razumeti, kako delujejo programi Linux ali Unix in kako jih strukturirati za visoko zmogljivost.
Linux je strežniška soba operacijski sistem in najpogosteje se vaše aplikacije izvajajo na tem OS. Čeprav rečem "Linux", lahko večino časa varno domnevate, da mislim na vse Unixu podobne operacijske sisteme na splošno. Vendar pa spremne kode nisem testiral na drugih sistemih. Torej, če vas zanima FreeBSD ali OpenBSD, se lahko vaši rezultati razlikujejo. Ko poskusim nekaj, kar je specifično za Linux, to opozorim.
Čeprav lahko to znanje uporabite za izdelavo aplikacije iz nič in bo ta popolnoma optimizirana, je najbolje, da tega ne storite. Če pišete nov spletni strežnik v C ali C++ za poslovno aplikacijo vaše organizacije, je to morda vaš zadnji dan v službi. Vendar pa bo poznavanje strukture teh aplikacij pomagalo pri izbiri obstoječih programov. Sisteme, ki temeljijo na procesih, boste lahko primerjali s sistemi, ki temeljijo na nitih, pa tudi na dogodkih. Razumeli in cenili boste, zakaj Nginx deluje bolje kot Apache httpd, zakaj lahko aplikacija Python, ki temelji na Tornadu, služi več uporabnikom v primerjavi z aplikacijo Python, ki temelji na Djangu.
ZeroHTTPd: Orodje za učenje
ZeroHTTPd je spletni strežnik, ki sem ga napisal iz nič v C kot učno orodje. Nima zunanjih odvisnosti, vključno z dostopom do Redisa. Izvajamo lastne postopke Redis. Glejte spodaj za več podrobnosti.
Čeprav bi lahko na dolgo razpravljali o teoriji, ni nič boljšega od pisanja kode, njenega izvajanja in primerjave vseh strežniških arhitektur med seboj. To je najbolj očitna metoda. Zato bomo napisali preprost spletni strežnik ZeroHTTPd z uporabo vsakega modela: na osnovi procesa, na osnovi niti in na podlagi dogodkov. Oglejmo si vsakega od teh strežnikov in poglejmo, kako delujejo v primerjavi med seboj. ZeroHTTPd je implementiran v eni sami datoteki C. Strežnik na podlagi dogodkov vključuje uthash, odlična implementacija zgoščene tabele, ki je na voljo v eni sami datoteki glave. V drugih primerih ni odvisnosti, da ne bi komplicirali projekta.
V kodi je veliko komentarjev, ki vam pomagajo razumeti. Ker je ZeroHTTPd preprost spletni strežnik v nekaj vrsticah kode, je tudi minimalno ogrodje za spletni razvoj. Ima omejeno funkcionalnost, vendar lahko streže statične datoteke in zelo preproste "dinamične" strani. Moram reči, da je ZeroHTTPd dober za učenje ustvarjanja visoko zmogljivih aplikacij za Linux. Na splošno večina spletnih storitev čaka na zahteve, jih preverja in obdeluje. Točno to bo storil ZeroHTTPd. To je orodje za učenje, ne za proizvodnjo. Ni dober pri obravnavanju napak in verjetno se ne bo ponašal z najboljšimi varnostnimi praksami (o ja, uporabil sem strcpy) ali premetene zvijače jezika C. Vendar upam, da dobro opravlja svoje delo.
Domača stran ZeroHTTPd. Lahko izpiše različne vrste datotek, vključno s slikami
Aplikacija Knjiga gostov
Sodobne spletne aplikacije običajno niso omejene na statične datoteke. Imajo zapletene interakcije z različnimi bazami podatkov, predpomnilniki itd. Zato bomo ustvarili preprosto spletno aplikacijo, imenovano "Knjiga gostov", kjer obiskovalci puščajo vnose pod svojim imenom. V knjigi gostov so shranjeni vnosi, ki ste jih pustili prej. Na dnu strani je tudi števec obiskovalcev.
Spletna aplikacija "Knjiga gostov" ZeroHTTPd
Števec obiskovalcev in vnosi v knjigo gostov so shranjeni v Redisu. Za komunikacijo z Redisom so implementirani lastni postopki, ki niso odvisni od zunanje knjižnice. Nisem velik oboževalec uvajanja homebrew kode, če obstajajo javno dostopne in dobro preizkušene rešitve. Toda namen ZeroHTTPd je preučevanje zmogljivosti Linuxa in dostopa do zunanjih storitev, medtem ko ima streženje zahtev HTTP resen vpliv na zmogljivost. Popolnoma moramo nadzorovati komunikacijo z Redisom v vsaki od naših strežniških arhitektur. V nekaterih arhitekturah uporabljamo blokiranje klicev, v drugih pa postopke, ki temeljijo na dogodkih. Uporaba zunanje odjemalske knjižnice Redis ne bo zagotovila tega nadzora. Poleg tega naš mali odjemalec Redis izvaja le nekaj funkcij (pridobivanje, nastavitev in povečanje ključa; pridobivanje in dodajanje matriki). Poleg tega je protokol Redis izjemno eleganten in preprost. Niti ga ni treba posebej učiti. Že dejstvo, da protokol vse delo opravi v približno stotih vrsticah kode, pove, kako dobro je premišljen.
Naslednja slika prikazuje, kaj aplikacija naredi, ko odjemalec (brskalnik) zahteva /guestbookURL.
Kako deluje aplikacija knjiga gostov
Ko je treba izdati stran knjige gostov, obstaja en klic v datotečni sistem za branje predloge v pomnilnik in trije omrežni klici v Redis. Datoteka predloge vsebuje večino vsebine HTML za stran na zgornjem posnetku zaslona. Obstajajo tudi posebna mesta za dinamični del vsebine: objave in števec obiskovalcev. Prejmemo jih od Redisa, jih vstavimo na stran in naročniku posredujemo v celoti oblikovano vsebino. Tretjemu klicu Redisa se je mogoče izogniti, ker Redis vrne novo vrednost ključa, ko se poveča. Vendar je za naš strežnik, ki ima asinhrono arhitekturo, ki temelji na dogodkih, veliko omrežnih klicev dober preizkus za učne namene. Zato zavržemo Redisovo vrnjeno vrednost števila obiskovalcev in jo poizvedujemo z ločenim klicem.
Strežniške arhitekture ZeroHTTPd
Gradimo sedem različic ZeroHTTPd z enako funkcionalnostjo, vendar različnimi arhitekturami:
Učinkovitost vsake arhitekture merimo tako, da strežnik naložimo z zahtevami HTTP. Toda pri primerjavi zelo vzporednih arhitektur se število poizvedb poveča. Testiramo trikrat in izračunamo povprečje.
Metodologija testiranja
Nastavitev testiranja obremenitve ZeroHTTPd
Pomembno je, da se pri izvajanju testov vse komponente ne izvajajo na istem stroju. V tem primeru ima operacijski sistem dodatne stroške razporejanja, saj komponente tekmujejo za CPE. Merjenje stroškov operacijskega sistema za vsako od izbranih strežniških arhitektur je eden najpomembnejših ciljev te vaje. Dodajanje več spremenljivk bo škodovalo procesu. Zato nastavitev na zgornji sliki deluje najbolje.
Kaj počne vsak od teh strežnikov?
load.unixism.net: Tukaj tečemo ab, pripomoček Apache Benchmark. Ustvarja obremenitev, potrebno za testiranje naših strežniških arhitektur.
nginx.unixism.net: Včasih želimo zagnati več kot en primerek strežniškega programa. Če želite to narediti, strežnik Nginx z ustreznimi nastavitvami deluje kot izravnalnik obremenitve, ki prihaja iz ab na procese našega strežnika.
zerohttpd.unixism.net: Tukaj izvajamo naše strežniške programe na sedmih različnih arhitekturah, eno za drugo.
redis.unixism.net: Ta strežnik poganja demon Redis, kjer so shranjeni vnosi v knjigo gostov in števci obiskovalcev.
Vsi strežniki delujejo na istem procesorskem jedru. Ideja je oceniti največjo zmogljivost vsake arhitekture. Ker so vsi strežniški programi testirani na isti strojni opremi, je to osnova za primerjavo. Moja testna nastavitev je sestavljena iz virtualnih strežnikov, najetih pri Digital Ocean.
Kaj merimo?
Izmerite lahko različne kazalnike. Zmogljivost vsake arhitekture v določeni konfiguraciji ocenimo tako, da strežnike naložimo z zahtevami na različnih ravneh vzporednosti: obremenitev naraste z 20 na 15 sočasnih uporabnikov.
Rezultati testiranja
Naslednja tabela prikazuje zmogljivost strežnikov v različnih arhitekturah na različnih ravneh vzporednosti. Y-os je število zahtev na sekundo, x-os so vzporedne povezave.
Spodaj je tabela z rezultati.
zahtev na sekundo
vzporednost iterativno vilice pred vilicami pretakanje predhodno pretakanje Anketa 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
velik razpon
2138
5000
-
velik razpon
1600
1100
2519
-
2235
8000
-
-
1200
velik razpon
2451
-
2100
10
-
-
velik razpon
-
2200
-
2200
11
-
-
-
-
2200
-
2122
12
-
-
-
-
970
-
1958
13
-
-
-
-
730
-
1897
14
-
-
-
-
590
-
1466
15
-
-
-
-
532
-
1281
Iz grafa in tabele je razvidno, da imamo nad 8000 hkratnimi zahtevami le še dva igralca: pre-fork in epoll. Ko se obremenitev poveča, strežnik, ki temelji na anketi, deluje slabše kot pretočni. Arhitektura pred ustvarjanjem niti je vreden tekmec epollu, kar dokazuje, kako dobro jedro Linuxa načrtuje veliko število niti.
Izvorna koda ZeroHTTPd
Izvorna koda ZeroHTTPd tukaj. Za vsako arhitekturo obstaja ločen imenik.
Poleg sedmih imenikov za vse arhitekture sta v imeniku najvišje ravni še dva: public in templates. Prva vsebuje datoteko index.html in sliko s prvega posnetka zaslona. Tja lahko postavite druge datoteke in mape, ZeroHTTPd pa bi moral brez težav streči te statične datoteke. Če se pot v brskalniku ujema s potjo v javni mapi, ZeroHTTPd poišče datoteko index.html v tem imeniku. Vsebina za knjigo gostov se generira dinamično. Ima samo domačo stran, njena vsebina pa temelji na datoteki 'templates/guestbook/index.html'. ZeroHTTPd enostavno doda dinamične strani za razširitev. Ideja je, da lahko uporabniki dodajajo predloge v ta imenik in po potrebi razširijo ZeroHTTPd.
Če želite zgraditi vseh sedem strežnikov, zaženite make all iz imenika najvišje ravni - in vse gradnje bodo prikazane v tem imeniku. Izvršljive datoteke iščejo javne imenike in imenike predlog v imeniku, iz katerega so zagnane.
API za Linux
Za razumevanje informacij v tem nizu člankov vam ni treba dobro poznati API za Linux. Vendar priporočam, da preberete več o tej temi, saj je na internetu veliko referenčnih virov. Čeprav se bomo dotaknili več kategorij API-jev za Linux, se bomo osredotočili predvsem na procese, niti, dogodke in omrežni sklad. Poleg knjig in člankov o API-ju za Linux priporočam tudi branje mane za sistemske klice in uporabljene knjižnične funkcije.
Zmogljivost in razširljivost
Ena opomba o zmogljivosti in razširljivosti. Teoretično med njima ni povezave. Lahko imate spletno storitev, ki deluje zelo dobro, z odzivnim časom nekaj milisekund, vendar se sploh ne prilagaja. Podobno lahko obstaja slabo delujoča spletna aplikacija, ki potrebuje nekaj sekund, da se odzove, vendar se poveča na desetine, da lahko obravnava več deset tisoč sočasnih uporabnikov. Vendar pa je kombinacija visoke zmogljivosti in razširljivosti zelo močna kombinacija. Visokozmogljive aplikacije na splošno varčno uporabljajo vire in tako učinkovito služijo več sočasnim uporabnikom na strežniku, kar zmanjšuje stroške.
CPE in I/O naloge
Končno sta v računalništvu vedno dve možni vrsti nalog: za I/O in CPE. Prejemanje zahtev prek interneta (omrežni V/I), strežba datotek (omrežni in diskovni V/I), komunikacija z bazo podatkov (omrežni in diskovni V/I) so vse V/I dejavnosti. Nekatere poizvedbe v zbirki podatkov so lahko nekoliko zahtevne za CPE (razvrščanje, povprečenje milijona rezultatov itd.). Večina spletnih aplikacij je omejena z največjim možnim V/I, procesor pa se redko uporablja s polno zmogljivostjo. Ko vidite, da neka V/I naloga uporablja veliko CPE, je to najverjetneje znak slabe arhitekture aplikacije. To lahko pomeni, da se viri procesorja zapravljajo za upravljanje procesov in preklapljanje konteksta - to pa ni povsem uporabno. Če delate nekaj, kot je obdelava slik, pretvorba zvočnih datotek ali strojno učenje, potem aplikacija zahteva zmogljive vire procesorja. Toda za večino aplikacij to ne drži.