Linux hálózati alkalmazások teljesítménye. Bevezetés

A webalkalmazásokat manapság szerte a világban használják, és az összes szállítási protokoll közül a HTTP dominál. A webalkalmazások fejlesztésének árnyalatait tanulmányozva a legtöbben nagyon kevés figyelmet fordítanak arra az operációs rendszerre, ahol ezek az alkalmazások valójában futnak. A fejlesztés (Dev) és üzemeltetés (Ops) elkülönítése csak rontotta a helyzetet. De a DevOps kultúra elterjedésével a fejlesztők elkezdik vállalni a felelősséget az alkalmazásaik felhőben történő futtatásáért, így rendkívül hasznos számukra, hogy alaposan megismerjék az operációs rendszer háttérfolyamatát. Ez különösen hasznos, ha olyan rendszert próbálunk telepíteni, amely ezrek vagy akár tízezrek egyidejű kapcsolódását kezeli.

A webszolgáltatások korlátai nagyon hasonlóak más alkalmazások korlátaihoz. Legyen szó terheléselosztókról vagy adatbázis-szerverekről, mindezen alkalmazásoknak hasonló problémáik vannak a nagy teljesítményű környezetben. Ezeknek a fundamentális korlátoknak a megértése és a megoldásukra vonatkozó módszerek összességében lehetővé teszi az Ön webalkalmazásainak teljesítményének és skálázhatóságának értékelését.

Ezt a cikksorozatot fiatal fejlesztők kérdéseire válaszul írom, akik jól informált rendszerszerkezetekké szeretnének válni. Nem lehet világosan megérteni a Linux alkalmazások optimalizálási módszereit anélkül, hogy elmélyülnénk az alapjaikban, vagy abban, hogyan működnek az operációs rendszer szintjén. Bár sokféle alkalmazást találunk, ebben a ciklusban a hálózati alkalmazásokra, nem pedig asztali szoftverekre, például böngészőre vagy szövegszerkesztőre szeretnék fókuszálni. Ez az anyag olyan fejlesztőknek és építészeknek készült, akik meg akarják érteni, hogyan működnek a Linux vagy Unix programok, és hogyan struktúrálják őket a magas teljesítmény érdekében.

A Linux szerver operációs rendszer, és a legtöbb esetben az alkalmazásai pontosan ezen az operációs rendszeren futnak. Bár azt mondom „Linux”, a legtöbb időben magabiztosan feltételezheti, hogy az összes Unix-szerű operációs rendszerre vonatkozik. Azonban nem teszteltem a mellékelt kódot más rendszereken. Tehát, ha érdekli a FreeBSD vagy az OpenBSD, az eredmények eltérőek lehetnek. Amikor valamit a Linux-ra jellemzően próbálok ki, azt külön is jelzem.

Bár az így megszerzett tudást felhasználhatja egy alkalmazás nulláról való létrehozására, és az csodálatosan optimalizált lehet, jobb ezt nem tenni. Ha új webszolgáltatót ír C vagy C++ nyelven a szervezetének üzleti alkalmazásához, lehet, hogy ez lesz az utolsó munkanapja. Azonban az ilyen alkalmazások felépítésének ismerete segít a már létező programok kiválasztásában. Képessé válik összehasonlítani a folyamat alapú rendszereket a szálalapú, valamint az esemény alapú rendszerekkel. Megérti és értékeli, miért működik jobban a Nginx, mint az Apache httpd, és hogy miért tud egy Tornado-alapú Python alkalmazás több felhasználót kiszolgálni, mint egy Django-alapú Python alkalmazás.

ZeroHTTPd: tanulási eszköz

ZeroHTTPd — egy webszolgáltató, amelyet nulláról írtam C nyelven oktatási eszközként. Nincsenek külső függőségei, beleértve a Redis hozzáférését is. Saját Redis eljárásainkat futtatjuk. Részletek lent.

Bár sokáig beszélhetnénk a elméletről, nincs jobb, mint kódot írni, futtatni azt, és összehasonlítani az összes szerverarchitektúrát. Ez a legegyértelműbb módszer. Ezért egy egyszerű ZeroHTTPd webszolgáltatót fogunk írásba venni, alkalmazva minden modellt: folyamat, szál és esemény alapú. Megvizsgáljuk ezeket a szervereket, és megnézzük, hogyan működnek egymással összehasonlítva. A ZeroHTTPd egy C fájlban valósult meg. Az esemény alapú szerver tartalmazza uthash, egy nagyszerű hash-tábla megvalósítás, amely egy fejlécfájlban érkezik. Más esetekben nincsenek függőségek, hogy ne bonyolítsuk a projektet.

A kódban rengeteg komment található, hogy segítsen eligibilitási folyamaton. Mint egy egyszerű webszolgáltató, amely néhány sor kódból áll, a ZeroHTTPd egy minimális keretrendszer a webfejlesztéshez is. Korlátozott funkcionalitással bír, de képes statikus fájlokat és nagyon egyszerű "dinamikus" oldalakat kiszolgálni. Meg kell mondanom, hogy a ZeroHTTPd jól alkalmazható a nagy teljesítményű Linux-alkalmazások létrehozásának tanulmányozására. Alapvetően a legtöbb webszolgáltatás várja a kéréseket, ellenőrzi azokat és feldolgozza. Ezt fogja tenni a ZeroHTTPd. Ez egy tanulási eszköz, és nem produkciós célokra. Nem erős a hibakezelésben, és valószínűleg nem büszkélkedhet a legjobb biztonsági gyakorlatokkal (igen, használtam strcpy) vagy bonyolult C nyelvi trükkökkel. De remélem, hogy jól teljesít a feladatán.

Linux hálózati alkalmazások teljesítménye. Bevezetés
A ZeroHTTPd kezdőlapja. Különböző fájltípusokat tud szolgáltatni, beleértve a képeket is.

Vendégkönyv alkalmazás

A modern webalkalmazások általában nem korlátozódnak statikus fájlokra. Komplex interakciókkal rendelkeznek különböző adatbázisokkal, cache-ekkel stb. Ezért létrehozunk egy egyszerű webalkalmazást, amelynek neve 'Vendégkönyv', ahol a látogatók feljegyzéseket hagyhatnak neveik alatt. A vendégkönyv megőrzi a korábban hagyott bejegyzéseket. Az oldal alján található egy látogatószámláló is.

Linux hálózati alkalmazások teljesítménye. Bevezetés
ZeroHTTPd 'Vendégkönyv' webalkalmazás

A látogatószámláló és a vendégkönyv bejegyzései Redisben tárolódnak. A Redishez való kommunikáció saját eljárásainkon keresztül történik, amelyek nem függnek külső könyvtáraktól. Nem vagyok nagy rajongója saját kód indításának, amikor jól bevált, nyilvános megoldások léteznek. De a ZeroHTTPd célja a Linux teljesítményének és a külső szolgáltatásokhoz való hozzáférésnek a tanulmányozása, míg a HTTP-kérések kezelésének komoly hatása van a teljesítményre. Teljes ellenőrzés alatt kell tartanunk a Redishez való kommunikációt minden szerverarchitektúránkban. Az egyik architektúrában blokkoló hívásokat használunk, másokban pedig eseményalapú eljárásokat. A külső Redis klienskönyvtár használata nem adna ilyen ellenőrzést. Ezen kívül, a kis Redis kliensünk mindössze néhány funkciót lát el (kulcs lekérése, beállítása és növelése; tömbhöz való hozzáadás és lekérése). Ezen felül, a Redis protokoll rendkívül elegáns és egyszerű. A tanulmányozásához különösebben nem szükséges. Az a tény, hogy a protokoll minden munkáját körülbelül száz kódsoron végzi, azt mutatja, mennyire jól meg van tervezve.

A következő ábra bemutatja az alkalmazás működését, amikor az ügyfél (böngésző) kérést küld. /guestbookURL.

Linux hálózati alkalmazások teljesítménye. Bevezetés
A vendégkönyv alkalmazás működési mechanizmusa

Amikor ki kell adni a vendégkönyv oldalát, egy hívás történik a fájlrendszerhez a sablon betöltésére, és három hálózati hívás a Redis-hoz. A sablonfájl tartalmazza a legtöbb HTML tartalmat az oldalon, ami a fenti képernyőképen látható. Van benne néhány speciális helyettesítő a dinamikus tartalmi részhez: bejegyzések és látogatószámláló. Ezeket a Redis-ból szerzünk be, beillesztjük az oldalra, és teljesen elkészített tartalommal adjuk át az ügyfélnek. A Redis harmadik hívása elkerülhető, mivel a Redis az új értéket adja vissza a kulcs növelésekor. Azonban az eseményalapú, aszinkron architektúrájú szerverünknél a sok hálózati hívás jó teszt a tanulási célok érdekében. Így elvetjük a Redis látogatószám értékét, és külön hívásban kérjük le azt.

ZeroHTTPd szerver architektúrák

Hét verziót építünk a ZeroHTTPd-ból, amelyek azonos funkcionalitással rendelkeznek, de különböző architektúrákkal:

  • Iteratív
  • Fork szerver (egy gyermekfolyamat a kéréshez)
  • Pre-fork szerver (folyamatok előzetes fork-olása)
  • Szálakkal rendelkező szerver (egy szál kérésenként)
  • Előre létrehozott szálakkal rendelkező szerver
  • Alapú architektúra poll()
  • Alapú architektúra epoll

Mérjük minden architektúra teljesítményét, HTTP-kérésekkel terhelve a szervert. Azonban a magas fokú párhuzamossággal rendelkező architektúrák összehasonlításakor a kérések száma növekszik. Három alkalommal teszteljük, és kiszámítjuk az átlagot.

Tesztelési módszertan

Linux hálózati alkalmazások teljesítménye. Bevezetés
ZeroHTTPd terheléses tesztelési beállítás

Fontos, hogy a tesztek végrehajtása során minden komponens ne egy gépen fusson. Ekkor az operációs rendszer extra költségeket visel a tervezés szempontjából, mivel a komponensek versenyeznek a CPU-ért. Az operációs rendszer költségeinek mérése a kiválasztott szerverarchitektúrák mindegyikével a gyakorlat egyik legfontosabb célja. Túl sok változó hozzáadása hátrányos hatással lesz a folyamatra. Ezért a fenti ábrán látható beállítás működik a legjobban.

Mit csinál mindegyik szerver

  • load.unixism.net: itt futtatjuk ab, az Apache Benchmark eszközt. Ez szolgáltatja a szükséges terhelést a szerverarchitektúráink teszteléséhez.
  • nginx.unixism.net: néha több példányt szeretnénk futtatni a szerverprogramból. Ehhez az Nginx megfelelő beállításokkal terheléselosztóként működik, amely a ab szerverfolyamatainkhoz érkezik.
  • zerohttpd.unixism.net: itt hétszer különböző architektúrákon futtatjuk szerverprogramjainkat, egyszerre egyet.
  • redis.unixism.net: ezen a szerveren Redis démon működik, ahol a vendégkönyv bejegyzései és a látogatószámláló tárolódnak.

Minden szerver egy processzormaggal működik. Az ötlet az, hogy értékeljük az egyes architektúrák maximális teljesítményét. Mivel minden szerverprogramot ugyanazon a hardveren tesztelnek, ez az alap szint a összehasonlításukhoz. A tesztkörnyezetem virtuális szerverekből áll, amelyeket a Digital Ocean-tól béreltem.

Mit mérünk?

Különböző mutatókat mérhetünk. Értékeljük az egyes architektúrák teljesítményét a megadott konfigurációban, a szerverek terhelésével különböző párhuzamossági szinteken: a terhelés 20-tól 15 000 egyidejű felhasználóig nő.

A teszteredmények

A következő diagramon a szerverek teljesítménye látható különböző architektúrákon, különböző párhuzamossági szintek mellett. Az y tengelyen a másodpercenkénti lekérdezések száma, az x tengelyen a párhuzamos kapcsolatok láthatók.

Linux hálózati alkalmazások teljesítménye. Bevezetés

Linux hálózati alkalmazások teljesítménye. Bevezetés

Linux hálózati alkalmazások teljesítménye. Bevezetés

Az alábbiakban táblázat található az eredményekkel.

lekérdezések másodpercenként

párhuzamosság
iteratív
fork
elő-fork
szálas
elő-szálas
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
nagy szórás
2138

5000
–
nagy szórás
1600
1100
2519
–
2235

8000
–
–
1200
nagy szórás
2451
–
2100

10 000
–
–
nagy szórás
–
2200
–
2200

11 000
–
–
–
–
2200
–
2122

12 000
–
–
–
–
970
–
1958

13 000
–
–
–
–
730
–
1897

14 000
–
–
–
–
590
–
1466

15 000
–
–
–
–
532
–
1281

A grafikonból és a táblázatból látható, hogy 8000 egyidejű lekérdezés felett csak két szereplő marad: az elő-fork és az epoll. A hálózati terhelés növekedésével a poll alapú szerver teljesítménye rosszabb, mint a szálas. Az elő-szálas architektúra méltó versenytársa az epoll-nak: ez bizonyítja, mennyire jól tervezi meg a Linux mag a nagy számú szálat.

A ZeroHTTPd forráskódja

A ZeroHTTPd forráskódja itt. Minden architektúrához külön könyvtár tartozik.

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

A hét architektúra mappa mellett a legfelső szinten még két mappa található: public és templates. Az előbbi tartalmazza az index.html fájlt és az első képernyőkép képet. Ide más fájlokat és mappákat lehet elhelyezni, és a ZeroHTTPd problémamentesen kiadja ezeket a statikus fájlokat. Ha a böngészőben a path megfelel a public mappában található útnak, akkor a ZeroHTTPd ebben a mappában keresi az index.html fájlt. A vendégkönyvhöz készült tartalom dinamikusan generálódik. Csak egy kezdőlapja van, amelynek tartalma a 'templates/guestbook/index.html' fájlon alapul. A ZeroHTTPd könnyen bővíthető dinamikus oldalakkal. Az elképzelés az, hogy a felhasználók sablonokat adhatnak hozzá ebben a mappában, és szükség szerint bővíthetik a ZeroHTTPd-t.

A hét szerver összeszereléséhez futtassa make all a legfelső szintű mappából - és minden build megjelenik ebben a mappában. A végrehajtható fájlok a public és templates mappákat keresik abban a mappában, ahonnan futnak.

Linux API

Ahhoz, hogy megértse az ebben a cikksorozatban található információkat, nem feltétlenül szükséges alaposan érteni a Linux API-t. Javaslom, hogy olvasson többet erről a témáról, számos referencia áll rendelkezésre az interneten. Bár néhány Linux API kategóriát érinteni fogunk, a figyelmünk főként a folyamatokra, szálakra, eseményekre és a hálózati stackre összpontosít. A Linux API-ról szóló könyvek és cikkek mellett ajánlom, hogy nézze át a rendszerhívások és a használt könyvtári funkciók man oldalait is.

Teljesítmény és skálázhatóság

Egy megjegyzés a teljesítményről és a skálázhatóságról. Elméletileg nincs köztük közvetlen kapcsolat. Lehet egy olyan webszolgáltatás, amely nagyon jól működik, néhány millisekundumos válaszidővel, de egyáltalán nem skálázható. Hasonlóképpen lehet egy rosszul működő webalkalmazás, amely válaszra több másodpercet igényel, de skálázható tucatnyira, hogy kezeljen ezernyi egyidejű felhasználót. Ennek ellenére a magas teljesítmény és a skálázhatóság kombinációja nagyon erős együttest alkot. A nagy teljesítményű alkalmazások általában takarékosan használják az erőforrásokat, így hatékonyan szolgálnak ki több egyidejű felhasználót a szerveren, csökkentve a költségeket.

CPU és I/O feladatok

Végül a számítások során mindig két lehetséges feladat típust találunk: I/O és CPU. Az interneten keresztül érkező lekérdezések (hálózati bemeneti-kimeneti), fájlok kezelése (hálózati és lemezbemeneti-kimeneti), adatbázissal való kommunikáció (hálózati és lemezbemeneti-kimeneti) – mindez I/O tevékenység. Néhány adatbázis-lekérdezés kissé megterhelheti a CPU-t (rendezés, egymillió eredmény átlagának számítása stb.). A legtöbb webalkalmazás maximálisan korlátozva van az elérhető I/O-ra, míg a processzor ritkán működik teljes kapacitással. Ha azt látja, hogy egy I/O feladat sok CPU-t használ, akkor valószínűleg a rossz alkalmazásarchitektúra jele. Ez azt jelentheti, hogy a CPU erőforrásai a folyamatok kezelésére és a kontextusváltásra fordítódnak – ami nem túl hasznos. Ha valami olyasmit csinál, mint például képfeldolgozás, audiófájlok átkonvertálása vagy gépi tanulás, akkor az alkalmazás erősebb CPU erőforrásokat igényel. De a legtöbb alkalmazás esetében ez nem így van.

Részletesebben a szerverarchitektúrákról

  1. I. rész. Iteratív architektúra
  2. II. rész. Fork-szerverek
  3. III. rész. Pré-fork szerverek
  4. IV. rész. Folyamatvégrehajtási szerverek
  5. V. rész. Előre létrehozott szálakkal rendelkező szerverek
  6. VI. rész. Polling architektúra
  7. VII. rész. Epoll architektúra

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster