OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveriMēs atkal publicējam konferences ziņojuma transkriptu HighLoad++ 2016. gada 7.—8. novembrī, kas norisinājās Skolkovo pie Maskavas. Vladimirs Protasovs stāsta, kā paplašināt NGINX funkcionalitāti, izmantojot OpenResty un Lua.

Sveiki visiem, mani sauc Vladimirs Protasovs, es strādāju Parallels. Nedaudz pastāstīšu par sevi. Trīs ceturtdaļas sava mūža es veltu kodēšanai. Esmu kļuvis par programmētāju līdz pat kauliem: reizēm sapnī redzu kodu. Viena ceturtdaļa no dzīves — industriālā izstrāde, koda rakstīšana, kas nonāk tieši produkcijā. Kods, ko daži no jums izmanto, bet neiedomājas par to.

Lai jūs saprastu, cik slikti tas bija. Kad es biju jauniņais, es ierados, un man izsniedza divu terabaitu datu bāzes. Tagad visi runā par highload. Es gāju uz konferencēm, jautāju: "Cilvēki, pastāstiet, jums ir big data, viss ir forši? Cik jums tur ir bāzu?" Man atbildēja: "Mums ir 100 gigabaiti!" Es teicu: "Forši, 100 gigabaiti!" Bet domāju par sevi, kā nošaut sava pokera seju. Tu domā, jā, puiši ir forši, bet tad atgriežas un centies tikt galā ar šīm daudzu terabaitu datu bāzēm. Un tas — būdams jauniņais. Vai varat iedomāties, kāds tas bija trieciens?

Es zinu vairāk nekā 20 programmēšanas valodas. Tas ir tas, kas man bija jāapgūst darba procesā. Tev pasniedz kodu Erlang, C, C++, Lua, Python, Ruby un vēl citās valodās, un tev visam jāstrādā. Kopumā esmu iemācījies. Precīzu skaitu sarēķināt negūtos, bet kaut kur ap 20 skaitlis ir pazudis.

Tā kā visi klātesošie zina, kas ir Parallels un ar ko mēs nodarbojamies, es nerunāšu par to, cik forši esam un ko darām. Es tikai pastāstīšu, ka mums ir 13 biroju visā pasaulē, vairāk nekā 300 darbinieku, izstrāde Maskavā, Tallinā un Maltā. Ja ir vēlme, var doties un pārcelties uz Maltu, ja ziemā ir auksti un jāuzsilda mugura.

Konkrēti mūsu nodaļa raksta Python 2. Mēs nodarbojamies ar biznesu un mums nav laika ieviest modernās tehnoloģijas, tāpēc mums ir grūti. Mums ir Django, jo tajā ir viss, ko vajag, un nevajadzīgo mēs esam izņēmuši. Tāpat arī MySQL, Redis un NGINX. Mums ir daudz citu foršu lietu. Mums ir MongoDB, mums skraidām truši, mums ir daudz ko tikai nav — bet tas nav mans un es ar to nenodarbojos.

OpenResty

Par sevi esmu pastāstījis. Apskatīsim, par ko es šodien runāšu:

  • Kas ir OpenResty un kāpēc to izmantot?
  • Kāpēc izgatavot vēl vienu velosipēdu, kad mums ir Python, NodeJS, PHP, Go un citas foršas lietas, ar kurām visi ir apmierināti?
  • Un nedaudz piemēru no dzīves. Man nācās stipri saīsināt savu prezentāciju, jo tā man izmēra 3,5 stundas, tāpēc piemēru būs maz.

OpenResty ir NGINX. Grauzdams viņu, mēs iegūstam pilnvērtīgu tīmekļa serveri, kas ir labi uzrakstīts un strādā ātri. Es domāju, ka vairums no mums izmanto NGINX ražošanā. Jūs visi zināt, ka tas ir ātrs un foršs. Tajā ir izveidota lieliska sinhronā ievade/izvade, tāpēc mums nav jāpārveido, tāpat kā Python tas ir darīts ar gevent. Gevent ir foršs, lielisks, bet, ja jūs uzrakstīsiet C kodu un kaut kas noies greizi, ar gevent jūs sajuks prātā to labojot. Man bija tāda pieredze: vajadzēja divas dienas, lai saprastu, kas tur notika nepareizi. Ja kāds neiedziļinātos pirms tam pāris nedēļas, neatrastu problēmu, nenorakstītu to internetā un Google to neatklātu, mēs vispār varētu apjukt.

NGINX jau ir izveidota kešatmiņa un statiskais saturs. Jums nav jāuztraucas, kā to izdarīt cilvēciski, lai kaut kur nesamulsinātu, lai jūs kaut kur nezaudētu deskriptori. Nginx ir ļoti ērti izvietojams, jums nav jāpārdomā, ko ņemt - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx uzstādīts, administratoriem nodots, viņi zina, kā strādāt ar to. Nginx strukturēti apstrādā pieprasījumus. Par to nedaudz vēlāk pastāstīšu. Īsumā tam ir fāze, kad tas tikai saņem pieprasījumu, kad tas to apstrādā un kad nosūta saturu lietotājam.

Nginx ir foršs, bet ir viena problēma: tas nav pietiekami elastīgs, pat ar visām tām foršām funkcijām, ko puiši ir ielikusi konfigurācijā, neskatoties uz to, ka to var konfigurēt. Šī jauda ir nepietiekama. Tāpēc Taobao puiši pirms astoņiem gadiem iebūvēja tur Lua. Ko tas sniedz?

  • Izmērs. Tas ir mazs. LuaJIT nodrošina apmēram 100-200 kilobaitus atmiņas pārklājuma un minimālu veiktspējas pārklājumu.
  • ĀtrumsLuaJIT interpretators in many situations are close to C, in some situations they fall behind Java, and in others, they surpass it. For some time it was considered state of the art, an amazing JIT compiler. Now there are cooler options, but they are very heavy, for example, the same V8. Some JavaScript interpreters and the Java HotSpot are faster in some areas, but in certain places they still lag behind.
  • Vieglums apgūtIf you have, say, a codebase in Perl, and you are not Booking, you won't find Perl programmers. Because they are not available; everyone has taken them, and teaching them is long and difficult. If you're looking for programmers in something else, you might also have to retrain them or find completely new ones. With Lua, it's straightforward. Any junior can learn Lua in three days. It took me about two hours to understand it. After two hours, I was already writing production code. About a week later, it was directly deployed to production.

As a result, it looks like this:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

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

Piemēri

Enough of the lyrical part, let's move on to the code. Here’s a simple Hello World:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

What do we have here? This is an engine-specific location. We don't stress, we don't write our own routing, we don't take someone else's ready-made — we already have it in NGINX, we're living well and lazily.

content_by_lua_block is a block that indicates that we are delivering content using a Lua script. We take the engine-specific variable remote_addr and inject it into string.format. This is the same as sprintf, but in Lua, and it's correct. And we deliver it to the client.

As a result, it will look like this:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

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

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

It simply sits and waits. This isn’t very good. When 100,000 users come in, it becomes very hard for us. So let's create a simple application as an example. We will search for images, for instance, of cats. But we won’t just search; we will expand the keywords and if a user searches for 'kittens', we will find them cats, fluffballs, and so on. First, we need to get the request data on the backend. It looks like this:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Divas rindas ļauj jums iegūt GET parametrus, nekādu sarežģījumu. Tā mēs, pieņemsim, no datubāzes ar tabulu pēc atslēgas vārda un paplašinājuma iegūstam šo informāciju, izmantojot parasto SQL vaicājumu. Viss ir vienkārši. Tas izskatās šādi:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Pieslēdzam bibliotēku resty.mysql, kas mums jau ir komplektā. Mums nekas nav jāinstalē, viss ir gatavs. Norādām, kā pieslēgties, un veicam SQL vaicājumu:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Šeit ir nedaudz biedējoši, bet viss strādā. Šeit 10 – tas ir limits. Mēs iegūstam 10 ierakstus, mēs esam slinki, negribam rādīt vairāk. Par limitu SQL es aizmirsu.

Tālāk mēs atrodam attēlus visiem vaicājumiem. Mēs apkopojam virkni vaicājumu un aizpildām Lua tabulu, kas saucas reqs, un veicam ngx.location.capture_multi.

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Visi šie vaicājumi tiek izsūtīti paralēli, un mēs saņemam atbildes. Darba laiks ir vienāds ar lēnākās atbildes laiku. Ja viss tiek izpildīts 50 milisekundēs un mēs nosūtījām simtu vaicājumu, tad atbilde ieradīsies 50 milisekundēs.

Tā kā mēs esam slinki un negribam rakstīt HTTP apstrādi un kešēšanu, mēs liksim NGINX visu izdarīt mūsu vietā. Kā jūs redzējāt, tur bija vaicājums uz url/fetch, lūk, tas:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Mēs veicam vienkāršu proxy_pass, norādam, kur kešēt, kā to izdarīt, un viss darbojas.

Bet tā nav pietiekami, mums vēl ir jānodod dati lietotājam. Vienkāršākā ideja ir visu serializēt JSON formātā, viegli, divās rindās. Nododam Content-Type, nododam JSON.

Bet ir viena grūtība: lietotājam negribas lasīt JSON. Jāiesaista front-end izstrādātāji. Dažreiz mums negribas to sākumā darīt. Un SEO speciālisti teiks, ka, ja mēs meklējam attēlus, tad viņiem ir vienalga. Bet ja mēs viņiem dodam kādu saturu, tad viņi teiks, ka mūsu meklētāji neko neindeksē.

Ko ar to darīt? Pašsaprotami, mēs dosim lietotājam HTML. Pašu rokām ģenerēt – nav stilīgi, tāpēc mēs gribam izmantot šablonus. Tam ir bibliotēka lua-resty-template.

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Jūs, iespējams, redzējāt trīs biedējošas burti OPM. OpenResty nāk ar savu pakotņu pārvaldnieku, caur kuru var uzstādīt vēl virkni dažādu moduļu, tostarp lua-resty-template. Tas ir vienkāršs šablonu dzinējs, līdzīgs Django šabloniem. Tur var uzrakstīt kodu un veikt mainīgo ievietošanas.

Rezultātā viss izskatīsies aptuveni šādi:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Mēs ņēmām datus un iepriekšējā reizē izveidojām veidni divās rindās. Lietotājs ir apmierināts, saņēma kaķīšus. Tā kā mēs paplašinājām pieprasījumu, viņš saņēma arī jūras lauvu. Varbūt viņš tieši to meklēja, bet nevarēja pareizi formulēt savu pieprasījumu.

Viss ir lieliski, bet mēs esam izstrādē un nevēlamies šobrīd rādīt lietotājiem. Izveidosim autentifikāciju. Lai to izdarītu, aplūkosim, kā NGINX apstrādā pieprasījumus OpenResty terminos:

  • Pirmā fāze — access, kad lietotājs ir tikai ieradies, un mēs uz viņu paskatījāmies pēc virsrakstiem, IP adreses un citiem datiem. Ja viņš mums nepatīk, varam viņu nekavējoties atslēgt. To var izmantot autentifikācijai, vai, ja mums nāk ļoti daudz pieprasījumu, mēs varam tos viegli izslēgt šajā fāzē.
  • rewrite. Pārveidojam kādus pieprasījuma datus.
  • content. Nododam saturu lietotājam.
  • headers filter. Aizvietojam atbildes virsrakstus. Ja mēs esam izmantojuši proxy_pass, mēs varam pārveidot kādus virsrakstus pirms to nodošanas lietotājam.
  • body filter. Mēs varam aizvietot ķermeni.
  • log — žurnālfiksēšana. Varam rakstīt žurnālus Elasticsearch bez papildu slāņa.

Mūsu autentifikācija izskatīsies apmēram tā:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Mēs pievienosim to tam location, kuru mēs iepriekš aprakstījām, un ieliksim tur šādu kodu:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Mēs pārbaudām, vai mums ir cookie tokens. Ja nav, tad novirzām uz autentifikāciju. Lietotāji ir viltīgi un var uzminēt, ka jāsakārto cookie tokens. Tāpēc mēs to vēl noliksim Redis:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Darba kods ar Redis ir ļoti vienkāršs un ne ar ko neatšķiras no citām valodām. Turklāt visa ievade/izvade, gan tur, gan šeit, ir neblokējoša. Ja rakstāt sinhrono kodu, tas darbojas asinkroni. Pāris līdzīgi kā ar gevent, tikai izdarīts labi.

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Izveidosim pašu autentifikāciju:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Sakām, ka mums ir jālasa pieprasījuma ķermenis. Saņemam POST argumentus, pārbaudām, vai lietotājvārds un parole ir pareizi. Ja tie nav pareizi, tad novirzām uz autentifikāciju. Bet, ja tie ir pareizi, tad ierakstām token Redis:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Neaizmirstiet uzstādīt cookie, tas arī tiek izdarīts divās rindās:

OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Piemērs ir vienkāršs, teorētisks. Mēs, protams, neizveidosim pakalpojumu, kas rāda cilvēkiem kaķīšus. Lai gan, kas mūs zina. Tāpēc aplūkosim, ko var izdarīt ražošanā.

  • Minimalistisks aizmugurējais. Dažreiz mums nepieciešams izdot tikai pavisam nedaudz datu no backend — kurā vietā jāievieto datums, kur jāparāda kāds saraksts, jāpastāsta, cik šobrīd lietotāju ir vietnē, jāpievieno skaitītājs vai statistika. Ko nedaudz tādu. Minimālus elementus var paveikt ļoti viegli. Tas būs ātri, ērti un lieliski.
  • Datu priekšapstrāde. Dažreiz vēlamies iekļaut mūsu lapā reklāmu, un šo reklāmu mēs ņemam caur API pieprasījumiem. To ir ļoti viegli izdarīt tieši šeit. Mēs neapgrūtinām mūsu backend, kurš tāpat smagi strādā. Varam ņemt un salikt šeit. Mēs varam salīt kādu JS vai, tieši otrādi, to nošķelt, veikt noteiktu priekšapstrādi pirms nododam to lietotājam.
  • Fasāde mikroservisam. Tas ir arī ļoti labs gadījums, ko esmu realizējis. Iepriekš es strādāju uzņēmumā Tenzor, kas nodarbojas ar elektronisko atskaites sagatavošanu, nodrošinot atskaites aptuveni pusei juristu valstī. Mēs izveidojām pakalpojumu, kurā, izmantojot šo pašu mehānismu, tika izdarītas daudz lietu: maršrutizācija, autorizācija un citi.
    OpenResty var izmantot kā līmi jūsu mikroservisiem, kas nodrošinās vienotu piekļuvi visam un vienotu interfeisu. Tā kā mikroservisi var būt uzrakstīti dažādās valodās — šeit ir Node.js, šeit PHP, šeit Python, un šeit kaut kas uz Erlang — mēs saprotam, ka negribam pārkopēt to pašu kodu visur. Tāpēc OpenResty var pievienot priekšpusē.
  • Statistika un analītika. Parasti NGINX stāv ieejā, un visi pieprasījumi iet caur to. Tieši šajā vietā ir ļoti ērti savākt datus. Var kaut ko uzreiz aprēķināt un kaut kur nosūtīt, piemēram, uz Elasticsearch, Logstash vai vienkārši ierakstīt žurnālā un vēlāk nosūtīt kaut kur.
  • Vairāku lietotāju sistēmas. Piemēram, tiešsaistes spēles ir arī ļoti labi izveidot. Šodien Keiptaunā Aleksandrs Gladišs stāstīs, kā ātri prototipēt vairāku lietotāju spēli, izmantojot OpenResty.
  • Pieprasījumu filtrēšana (WAF). Pašlaik ir modē veidot dažādus web lietojumprogrammu ugunsmūrus, ir daudz pakalpojumu, kas tos piedāvā. Ar OpenResty var izveidot web lietojumprogrammu ugunsmūru, kas vienkārši un viegli filtrēs pieprasījumus pēc jūsu prasībām. Ja jums ir Python, tad saprotat, ka PHP noteikti nenozags, ja vien to neizpildīsiet no konsoles kaut kur. Jūs zināt, ka jums ir MySQL un Python. Droši vien šeit varētu mēģināt veikt kādu direktorija traversēšanas uzbrukumu un kaut ko ievietot datubāzē. Tādēļ var ātri un lēti filtrēt bīstamus pieprasījumus tieši frontē.
  • Kopiena. Tā kā OpenResty balstās uz NGINX, tam ir bonuss — tas NGINX kopiena. Tā ir ļoti liela, un ievērojama daļa jautājumu, kas jums radīsies sākumā, jau ir atrisināta NGINX kopienas.

    Lua izstrādātāji. Vakar runāju ar puikām, kuri ieradās uz mācību dienu HighLoad++ un dzirdēju, ka uz Lua ir uzrakstīts tikai Tarantool. Tas tā nav, uz Lua ir uzrakstīts daudz kas. Piemēri: OpenResty, XMPP serveris Prosody, spēļu dzinējs Love2D, Lua ir skriptēta Warcraft un citur. Lua izstrādātāju ir ļoti daudz, viņiem ir liela un atsaucīga kopiena. Visi mani jautājumi par Lua tika atrisināti dažu stundu laikā. Kad raksti sarakstā, burtiski dažu minūšu laikā jau ir kaudze atbilžu, izklāsta, kas un kā, kas pie kā. Tas ir ļoti jauki. Diemžēl ne visur ir tāda laipna un draudzīga kopiena.
    Par OpenResty ir GitHub, kur var izveidot issue, ja kaut kas ir bojāts. Ir saraksts uz Google Groups, kur var apspriest vispārējus jautājumus, ir saraksts ķīniešu valodā — nezini, varbūt angļu valodu neproti, bet nav šķēršļu ķīniešu valodai.

Secinājumi

  • Ceru, ka spēju izskaidrot, ka OpenResty ir ļoti ērta ietvarstruktūra, kas ir pielāgota tīmekļa izstrādei.
  • Tam ir zems piekļuves slieksnis, jo kods ir līdzīgs tam, ko mēs rakstām, valoda ir diezgan vienkārša un minimālistiska.
  • Tas piedāvā asinhronu I/O bez atgriezeniskās saites, mums nebūs 'nūdeles', kā dažreiz varam uzrakstīt NodeJS.
  • Tam ir viegla izvietošana, jo mums nepieciešams tikai NGINX ar nepieciešamo moduli un mūsu kods, un viss uzreiz darbojas.
  • Liela un atsaucīga kopiena.

Es nestāstīju sīkāk, kā notiek maršrutēšana, tur sanāk ļoti garš stāsts.

Paldies par uzmanību!

Atskaņot video

Vladimirs Protasovs — OpenResty: pārvēršam NGINX par pilnvērtīgu lietojumprogrammu serveri

Avots: habr.com
Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa hostingu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster