OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakításaÚjra közzétesszük a konferencia előadásának átírását HighLoad++ 2016, amely a moszkvai Skolkovo-ban zajlott 7–8-án, múlt év novemberében. Vlagyimir Protasov elmondja, hogyan lehet bővíteni az NGINX funkcionalitását az OpenResty és a Lua segítségével.

Üdvözlöm mindenkit, Vlagyimir Protasov vagyok, a Parallels-nél dolgozom. Mesélek egy kicsit magamról. Életem háromnegyedét kódírással töltöttem. Megszállott programozó lettem, szó szerint: néha álmomban is kódot látok. Életem egynegyedét ipari fejlesztésben töltöttem, olyan kódot írok, amely közvetlenül a gyártásba kerül. Az a kód, amit néhányan használtok, de nem is sejtitek.

Hogy megértsétek, mennyire rossz volt a helyzet. Amikor fiatal junior voltam, megérkeztem, és két terabájtos adatbázisokat kaptam. Most már mindenkinek highload van itt. Jártam a konferenciákra, és kérdeztem: „Fiúk, meséljetek, nektek big data van, minden szuper? Mekkora az adatbázisotok?” Azt válaszolták: „Nekünk 100 gigabájt van!” Én mondtam: „Szuper, 100 gigabájt!” Közben gondoltam, hogy meg kell tartanom a pókerarcot. Azt hitted, hogy a fiúk menők, aztán visszajössz, és vacakolsz ezekkel a sokterabájtos adatbázisokkal. És ez - junior koromban. El tudjátok képzelni, mekkora pofon volt ez?

Több mint 20 programozási nyelvet ismerek. Ez az, amivel dolgoznom kellett. Kapsz kódot Erlangban, C-ben, C++-ban, Luában, Pythonban, Rubiban, és még sok másban, és mindent meg kell csinálnod. Az összes nyelvet nem tudtam pontosan megszámolni, de körülbelül 20-nál elveszett a szám.

Mivel mindenki tudja, mi az a Parallels, és mivel foglalkozunk, nem fogom mondani, milyen klasszak vagyunk, és mit csinálunk. Csak annyit mondok, hogy 13 irodánk van világszerte, több mint 300 alkalmazottunk van, a fejlesztés Moszkvában, Tallinnban és Máltán zajlik. Ha akarod, költözhetsz Máltára, ha télen hideg van, és meg akarod melegíteni a hátadat.

A mi részlegünk konkrétan Python 2-őt használ. Üzlettel foglalkozunk, és nincs időnk divatos technológiák bevezetésére, így szenvedünk. Van Django, mert abban minden benne van, a fölösleget meg kivettük. Emellett MySQL, Redis és NGINX is. Továbbá sok más klassz dologgal rendelkezünk. Van MongoDB, nyuszi is van nálunk, szóval olyan dolgok, amik nincsenek – de ez nem az én hatásköröm, nem ezzel foglalkozom.

OpenResty

Meséltem magamról. Nézzük meg, miről fogok ma beszélni:

  • Mi az OpenResty, és mivel lehet fogyasztani?
  • Miért találjunk ki még egy kerékpárt, amikor ott van nekünk a Python, NodeJS, PHP, Go és sok más klassz dolog, amivel mindenki elégedett?
  • Egy kis példa az életből. Nagyon le kellett rövidítenem a beszámolómat, mert 3,5 órásra sikerült, ezért kevés példa lesz.

Az OpenResty az NGINX. Ennek köszönhetően van egy teljes értékű webkiszolgáló, ami jól van megírva, gyorsan működik. Azt hiszem, a többségünk az NGINX-et használja a termelésben. Mindenki tudja, hogy gyors és klassz. Nagyszerű szinkron bemenet/kimenetet valósítottak meg benne, így nem kell újra feltalálnunk a szelet, mint ahogy a Python esetében a geventtel megtették. A gevent klassz, szuper, de ha írsz C kódot, és valami nem úgy működik, ahogy kellene, akkor megőrülsz a hibakeresésnél. Volt tapasztalatom: két napomba telt, hogy kiderítsem, mi ment rosszul. Ha valaki előtte nem kutatott volna heteken át, nem találta volna meg a problémát, nem írt volna róla az Interneten, és a Google sem találta volna meg, akkor teljesen megőrültünk volna.

Az NGINX-ben már van cache-elés és statikus tartalom. Nem kell aggódnod, hogyan csináld ezt normálisan, hogy ne lassuljon le valahol, vagy ne veszítsd el a descriptorokat. Az Nginx-et nagyon könnyű telepíteni, nem kell azon gondolkodnod, mit válassz — WSGI, PHP-FPM, Gunicorn, Unicorn. Telepíted az Nginx-et, a rendszergazdák megkapják, ők tudják, hogyan kell bánni vele. Az Nginx strukturáltan kezeli a kéréseket. Erről később egy kicsit bővebben beszélek. Röviden: van egy fázis, amikor csak fogadta a kérést, amikor feldolgozta, és amikor visszaadta a tartalmat a felhasználónak.

Az Nginx klassz, de van egy probléma: nem elég rugalmas, még a sok klassz funkció ellenére, amit a fiúk beleraktak a konfigurációba, annak ellenére, hogy testre lehet szabni. Ebből a potenciálból hiányzik valami. Ezért a Taobao srácok régen, úgy nyolc éve, beépítették a Lua-t. Mit ad ez?

  • Méret. Kicsi. A LuaJIT körülbelül 100-200 kilobytes memória overheadet és minimális teljesítmény overheadet ad.
  • SebességA LuaJIT interpreter is often close to C in many situations, sometimes it falls behind Java, while in other cases it surpasses it. For a time, it was considered state of the art, the coolest JIT compiler. Today, there are more advanced ones, but they're very heavy, for example, V8. Some JS interpreters and Java's HotSpot are faster in certain areas, yet still lag behind in others.
  • Egyszerű megérteniIf you have, say, a codebase in Perl, and you're not Booking, you won't find Perl programmers. Because they are not available; they've all been taken, and teaching them is time-consuming and difficult. If you want programmers in something else, you may also need to retrain or find them. With Lua, it's straightforward. Any junior can learn Lua in three days. It took me about two hours to get the hang of it. After two hours, I was already writing production code. After about a week, it actually went into production.

As a result, it looks like this:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

There's a lot going on here. OpenResty brings together a bunch of modules, both Lua and engine-specific. And you have everything ready — you deploy it, and it works.

Példák

Enough with the poetry, let's get to the code. Here's a simple Hello World:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

What's here? That's an engine-specific location. We don't worry about it, we don't write our own routing, we don't take a pre-made one — we already have it in NGINX, and we're living well and lazily.

content_by_lua_block — is a block that indicates we are serving content using a Lua script. We take the engine variable remote_addr and plug it into string.format. It's the same as sprintf, just in Lua, just correctly. And we deliver it to the client.

As a result, it will look like this:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

But let's return to the real world. Nobody deploys Hello World to production. Our application usually interacts with a database or somewhere else and spends most of its time waiting for a response.

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

It just sits and waits. This isn't very good. When 100,000 users come in, it becomes quite challenging. Therefore, let's create a simple application as an example. We'll search for images, for instance, kittens. But we won't just search randomly; we'll extend keywords and, if a user searches for 'kittens', we'll find them cats, fluffy ones, and so on. First, we need to get the request data on the backend. It looks like this:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Két sor megengedi, hogy lekérjük a GET-paramétereket, semmi bonyolultság. Aztán mondjuk, az adatbázisból az kulcsszó és kiterjesztés táblájából egy szokásos SQL lekérdezéssel megkaptuk ezt az információt. Egyszerű. Így néz ki:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Csatlakoztatjuk a könyvtárat resty.mysql, ami már nálunk van. Nincs szükség semmit telepíteni, minden előkészített. Megadjuk, hogyan csatlakozzunk, és végzünk egy SQL lekérdezést:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Itt kicsit ijesztő, de minden működik. Itt a 10 a limit. 10 rekordot veszünk ki, lusták vagyunk, nem akarunk többet mutatni. Az SQL-ben elfelejtettem a limittel foglalkozni.

Aztán megtaláljuk a képeket minden lekérdezés alapján. Összegyűjtünk egy csomó lekérdezést és feltöltjük a Lua táblázatot, ami reqs, és végzünk ngx.location.capture_multi.

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Mindezek a lekérdezések párhuzamosan futnak, és visszakapjuk a válaszokat. A futási idő megegyezik a leglassabb válasz idejével. Ha mindegyik 50 milliszekundumban válaszol, és küldtünk száz lekérdezést, akkor a válasz 50 milliszekundum alatt érkezik.

Mivel lusták vagyunk, és nem akarunk HTTP kezelést és gyorsítótárazást írni, rábízzuk az NGINX-re, hogy mindent elintézzen helyettünk. Ahogy láttuk, ott volt egy lekérdezés a url/fetch, ez az:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Egyszerűen végzünk egy proxy_pass, megadjuk, hova kell gyorsítótárazni, hogyan kell ezt megcsinálni, és minden működik.

De ez nem elég, azt is el kell adnunk a felhasználónak. A legegyszerűbb ötlet, hogy mindent JSON-ba szerializáljunk, könnyen, két sorban. Megadjuk a Content-Type-ot, visszaadjuk a JSON-t.

De van egy nehézség: a felhasználó nem akar JSON-t olvasni. Meg kell nyernünk a frontendeseket. Néha kezdetben nem szeretnénk ezt csinálni. A SEO szakemberek is azt mondják, hogy ha képeket keresünk, nekik mindegy. De ha valamilyen tartalmat adunk át nekik, azt mondják, hogy a keresőmotorok nem indexelnek semmit.

Mit tegyünk ezzel? Nyilvánvalóan HTML-t fogunk adni a felhasználónak. Kézzel generálni - nem komilfo, ezért sablonokat szeretnénk használni. Erre van egy könyvtár lua-resty-template.

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Valószínűleg láttad a három ijesztő betűt OPM. Az OpenResty rendelkezik a saját csomagkezelőjével, amelyen keresztül rengeteg más modult lehet telepíteni, többek között lua-resty-template. Ez egy egyszerű sablonmotor, amely közel áll a Django sablonokhoz. Ott kódot lehet írni, és változókat behelyettesíteni.

Ennek eredményeként minden körülbelül így fog kinézni:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Adatokat gyűjtöttünk és a sablont ismét két sorban rendereltük. A felhasználó boldog, megkapta a macskákat. Mivel bővítettük a keresést, a kiscicák mellett még egy tengeri oroszlánt is kapott. Ki tudja, talán éppen őt kereste, de nem tudta megfogalmazni a keresését.

Minden szuper, de mi fejlesztés alatt állunk, és még nem szeretnénk a felhasználóknak megmutatni. Csak a bejelentkezést csináljuk meg. Ehhez nézzük meg, hogyan dolgozza fel az NGINX a kéréseket az OpenResty szempontjából:

  • Az első fázis — hozzáférés, amikor a felhasználó éppen csak megérkezett, és megnézzük őt a fejlécek, az IP-cím és egyéb adatok alapján. Azonnal elutasíthatjuk, ha nem tetszik nekünk. Ezt használhatjuk a bejelentkezéshez, vagy ha nagyon sok kérés érkezik, akkor ezen a fázison könnyen letudhatjuk azokat.
  • átírás. Átírjuk a kérés bizonyos adatait.
  • content. Továbbítjuk a tartalmat a felhasználónak.
  • fejléc szűrő. Megváltoztatjuk a válasz fejléceit. Ha használtuk a proxy_pass, bizonyos fejléceket átírhatunk, mielőtt a felhasználónak továbbítanánk azokat.
  • törzs szűrő. Megváltoztathatjuk a törzset.
  • naplózás — naplózás. Lehetőség van a naplók Elasticsearchbe írására további réteg nélkül.

A bejelentkezésünk körülbelül így fog kinézni:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Ezt hozzáadjuk ahhoz a location, amelyet korábban leírtunk, és beágyazzuk a következő kódot:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Megnézzük, van-e cookie token. Ha nincs, akkor átirányítjuk a bejelentkezésre. A felhasználók ravaszak és kitalálhatják, hogy be kell állítaniuk a cookie tokent. Ezért ezt még elhelyezzük a Redisben is:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

A Redis kezelésével kapcsolatos kód nagyon egyszerű, és semmiben sem különbözik más nyelvektől. Az összes bemenet/kimenet, legyen az ott vagy itt, nem blokkoló. Ha szinkron kódot írsz, akkor aszimmetrikusan működik. Kb. mint a gevent, csak jól csinálva.

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Készítsük el a bejelentkezést:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Mondjuk, hogy szükségünk van a kérés törzsének olvasására. Megkapjuk a POST-argumentumokat, ellenőrizzük, hogy a felhasználónév és a jelszó helyes-e. Ha nem helyes, akkor átirányítjuk a bejelentkezésre. Ha helyes, akkor a tokent beírjuk a Redisbe:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Ne felejtsük el beállítani a cookiet, ezt is két sorban megtehetjük:

OpenResty: a NGINX teljes értékű alkalmazásszerverré alakítása

Ez egy egyszerű, elméleti példa. Természetesen nem fogunk olyan szolgáltatást csinálni, ami macskákat mutat az embereknek. De ki tudja. Ezért nézzük meg, mit lehet csinálni a produkcióban.

  • Minimalista backend. Néha szükségünk van arra, hogy a backendből egy kicsit adatot kiadjuk: valahol dátumot kell behelyettesítenünk, valahol egy listát megjelenítenünk, megmondani, hány felhasználó van most az oldalon, csatlakoztatni egy számlálót vagy statisztikát. Valami ilyesmi, apró dolgokat nagyon könnyen meg lehet csinálni. Ezek minimális darabkák gyorsan, könnyedén és jól megoldhatók.
  • Adatok előfeldolgozása. Néha azt is szeretnénk, ha reklámokat integrálnánk az oldalunkba, amelyek API-hívások segítségével kerülnek beszerzésre. Ezt itt nagyon könnyű megcsinálni. Nem terheljük le a backendünket, amely már amúgy is nehezen dolgozik. Itt össze lehet állítani valamit. Össze tudunk rakni valamilyen JS-t vagy éppen ellenkezőleg, szétszedni valamit, amit előre kell feldolgozni, mielőtt a felhasználónak átadnánk.
  • Fasád egy mikroszolgáltatás számára. Ez is egy nagyon jó eset, én is megvalósítottam. Ezelőtt a Tenzor cégnél dolgoztam, amely elektronikus jelentéstétellel foglalkozik, és a jogi személyek körülbelül felének biztosítja a jelentéstételt az országban. Készítettünk egy szolgáltatást, ott ugyanezen mechanizma segítségével sok dolgot megoldottunk: útvonalirányítás, jogosultságkezelés és egyebek.
    Az OpenResty használható ragasztóként a mikroszolgáltatásaid számára, amely egységes hozzáférést és egységes felületet biztosít mindenhez. Mivel a mikroszolgáltatások íródhatnak úgy, hogy itt Node.js, ott PHP, itt Python, itt meg valami Erlangon fut, tudjuk, hogy nem akarjuk ugyanazt a kódot mindenhol átírni. Ezért az OpenResty-t be lehet illeszteni a frontendbe.
  • Statisztika és analitika. Általában az NGINX áll az előtérben, és az összes kérés rajta átfolyik. Pontosan ezen a helyen nagyon kényelmes összegyűjteni. Valamit azonnal ki lehet számolni és valahová küldeni, például a Elasticsearch-be, Logstash-ba, vagy egyszerűen csak rögzíteni a naplóba, majd később valahová elküldeni.
  • Többfelhasználós rendszerek. Például online játékokat is nagyon jól lehet csinálni. Ma Cape Townban Alekszandr Gladys ismertetni fogja, hogyan lehet gyorsan prototípusokat készíteni egy többfelhasználós játékhoz az OpenResty segítségével.
  • Kérések szűrése (WAF). Jelenleg divat a web application firewallok létrehozása, számos szolgáltatás áll rendelkezésre, amelyek ezt kínálják. Az OpenResty segítségével saját web application firewall-t készíthet, amely egyszerűen és könnyen szűri a kéréseket az Ön igényei szerint. Ha Python-t használ, tudja, hogy a PHP-t biztosan nem tudják injektálni, hacsak nem indítja el a konzolból valahol. Ön tudja, hogy van MySQL és Python. Valószínűleg valaki megpróbálhat valamilyen directory traversal-t csinálni, és valamit injektálni az adatbázisba. Ezért gyorsan és olcsón szűrheti a gyanús kéréseket közvetlenül a frontend-en.
  • Közösség. Mivel az OpenResty az NGINX alapján készült, ezért van egy bónusza - ez NGINX közösség. Nagyon nagy, és a kezdeti kérdések jelentős részét már megválaszolta az NGINX közösség.

    Lua fejlesztők. Tegnap beszélgettem olyan srácokkal, akik részt vettek a HighLoad++ tanulónapon, és hallottam, hogy a Lua-t csak a Tarantool-ban használták. Ez nem igaz, a Lua-t sok mindenre írták. Példák: OpenResty, Prosody XMPP-szerver, Love2D játékmotor, Lua scriptelhető a Warcraftban és más helyeken. Nagyon sok Lua fejlesztő van, nagy és válaszkész közösséggel. Minden kérdésemre a Lua-val pár órán belül választ kaptam. Amikor írsz az e-mail listára, néhány percen belül már egy csomó válasz érkezik, részletezve mi és hogyan, mit mivel. Ez igazán nagyszerű. Sajnos nem mindenhol van ilyen barátságos és segítőkész közösség.
    Az OpenResty-hez van GitHub, ahol problémát jelenthet, ha valami eltörik. Van egy Google Groups lista, ahol általános kérdéseket lehet megbeszélni, van egy kínai lista is - hátha nem beszél angolul, de tud kínaiul.

Összegzés

  • Remélem, sikerült kifejeznem, hogy az OpenResty egy nagyon kényelmes keretrendszer, amelyet webre terveztek.
  • Alacsony a belépési küszöb, mivel a kód hasonlít arra, amivel dolgozunk, a nyelv viszonylag egyszerű és minimalista.
  • Aszinkron I/O-t biztosít callback-ek nélkül, így nem lesz hosszan elágazott kód, mint amit néha a NodeJS-ben írunk.
  • Könnyű a telepítés, mivel csak az NGINX-re van szükség a megfelelő modulokkal és a kódunkra, és minden azonnal működik.
  • Nagy és válaszkész közösség.

Nem mondtam el részletesen, hogyan történik a routolás, mert az túl hosszú beszélgetést eredményezett volna.

Köszönöm a figyelmet!

Videó lejátszása

Vladimir Protasov - OpenResty: az NGINX-et teljes értékű alkalmazásszerverré alakítjuk

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