OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

OpenResty: pretvaranje NGINX-a u punopravni server aplikacijaPonovo objavljujemo transkript izvještaja sa konferencije HighLoad++ 2016. koji se održao u Skolkovu kod Moskve 7-8. novembra prošle godine. Vladimir Protasov objašnjava kako proširiti NGINX funkcionalnost sa OpenResty i Lua.

Pozdrav svima, zovem se Vladimir Protasov, radim u Parallelsu. Reći ću vam nešto o sebi. Provodim tri četvrtine svog života pišući kod. Postao sam programer do srži u doslovnom smislu: ponekad vidim kod u svojim snovima. Četvrtina života je industrijski razvoj, pisanje koda koji ide direktno u proizvodnju. Kod koji neki od vas koriste, ali ga ne shvaćaju.

Dakle, razumete koliko je bilo loše. Kada sam bio mlađi, došao sam i dobio sam ove baze podataka od dva terabajta. Sada je veliko opterećenje za sve. Išao sam na konferencije i pitao: „Momci, recite mi, imate velike podatke, je li sve cool? Koliko baza imate tamo? Odgovorili su mi: “Imamo 100 gigabajta!” Rekao sam: "Kul, 100 gigabajta!" I razmišljao sam u sebi kako da pažljivo održavam svoje poker lice. Misliš, da, momci su kul, a onda se vratiš i petljaš po ovim bazama podataka od više terabajta. A ovo je biti junior. Možete li zamisliti kakav je ovo udarac?

Znam više od 20 programskih jezika. To je nešto što sam morao da shvatim dok sam radio. Daju vam kod u Erlangu, C, C++, Lua, Python, Ruby, nečem drugom, i sve to morate iseći. Generalno, morao sam. Nije bilo moguće izračunati tačan broj, ali negdje oko 20. broj se izgubio.

Pošto svi prisutni znaju šta su Paralele i čime se bavimo, neću pričati o tome koliko smo cool i čime se bavimo. Reći ću vam samo da imamo 13 kancelarija širom sveta, više od 300 zaposlenih, razvoj u Moskvi, Talinu i na Malti. Ako želite, možete uzeti i preseliti se na Maltu ako je zimi hladno i trebate ugrijati leđa.

Konkretno, naš odjel piše u Pythonu 2. Mi smo u poslu i nemamo vremena za implementaciju modernih tehnologija, pa trpimo. Koristimo Django jer ima sve, a ono što je nepotrebno uzeli smo i bacili. Takođe MySQL, Redis i NGINX. Imamo i puno drugih cool stvari. Imamo MongoDB, imamo zečeve koji trče okolo, imamo sve - ali nije moje, i ja to ne radim.

OpenResty

Pričao sam o sebi. Hajde da shvatimo o čemu ću danas pričati:

  • Šta je OpenResty i sa čime se jede?
  • Zašto izmišljati još jedan točak kada imamo Python, NodeJS, PHP, Go i druge cool stvari sa kojima su svi zadovoljni?
  • I par primjera iz života. Morao sam dosta da skrećem izveštaj jer mi je trebalo 3,5 sata, tako da će biti malo primera.

OpenResty je NGINX. Zahvaljujući njemu, imamo kompletan web server koji je dobro napisan i brzo radi. Mislim da većina nas koristi NGINX u proizvodnji. Svi znate da je brz i kul. Napravili su cool sinhroni I/O u njemu, tako da ne moramo ništa da cikliramo, baš kao što su oni napravili gevent u Pythonu. Gevent je kul, odličan, ali ako napišete C kod i nešto krene po zlu, onda ćete s Geventom poludjeti ispravljanjem grešaka. Imao sam iskustvo: trebalo mi je dva dana da shvatim šta je tu pošlo po zlu. Da neko nije kopao nekoliko sedmica, pronašao problem, napisao na internetu, a Gugl ga nije našao, onda bismo potpuno poludjeli.

NGINX već ima urađeno keširanje i statički sadržaj. Ne morate da brinete kako to učiniti ljudski, da negdje ne usporite, da negdje ne izgubite deskriptore. Nginx je veoma zgodan za implementaciju, ne morate razmišljati šta da uzmete - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx je instaliran, dat adminima, oni znaju kako se radi s njim. Nginx obrađuje zahtjeve na strukturiran način. O ovome ću malo kasnije. Ukratko, ima fazu kada je samo prihvatio zahtjev, kada ga je obradio i kada je servirao sadržaj korisniku.

Nginx je kul, ali postoji jedan problem: nije dovoljno fleksibilan, čak i sa svim cool karakteristikama koje su momci ugurali u konfiguraciju, uprkos činjenici da se može konfigurisati. Ova moć nije dovoljna. Zato su momci sa Taobaoa, davno, čini se, pre osam godina, ugradili Luu u to. Šta to daje?

  • veličina. Mali je. LuaJIT daje oko 100-200 kilobajta memorije i minimalne performanse.
  • Brzina. LuaJIT interpreter je u mnogim situacijama blizak C-u, u nekim situacijama gubi od Jave, u drugim ga nadmašuje. Neko vrijeme se smatrao najmodernijim, najboljim JIT kompajlerom. Sada postoje i hladniji, ali su veoma teški, na primjer, isti V8. Neki JS interpretatori i Java HotSpot su u nekim trenucima brži, ali na nekim mjestima i dalje gube.
  • Lako se uči. Ako imate, recimo, bazu Perl kodova, a niste Booking, nećete naći Perl programere. Pošto ne postoje, svi su oduzeti, a podučavati ih je dugo i teško. Ako želite programere za nešto drugo, možda ćete ih morati ponovo obučiti ili pronaći. U slučaju Lue, sve je jednostavno. Svaki junior može naučiti Lua za tri dana. Trebalo mi je oko dva sata da to shvatim. Dva sata kasnije već sam pisao kod u produkciji. Otprilike nedelju dana kasnije otišao je pravo u proizvodnju i otišao.

Kao rezultat, to izgleda ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Ovde ima mnogo toga. OpenResty je prikupio gomilu modula, i luash i engine. I imate sve spremno - raspoređeno i radi.

primjeri

Dosta stihova, pređimo na kod. Evo malo Hello World:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

sta je tamo? Ovo je lokacija u Enginsu. Ne brinemo, ne pišemo vlastiti rut, ne uzimamo neki gotov – već ga imamo u NGINX-u, živimo dobar i lijen život.

content_by_lua_block je blok koji kaže da serviramo sadržaj koristeći Lua skriptu. Uzimamo Enginsovu varijablu remote_addr i stavi ga string.format. To je isto kao sprintf, samo u Lua, jedino ispravno. I dajemo ga klijentu.

Kao rezultat, to će izgledati ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

No, vratimo se u stvarni svijet. Niko ne implementira Hello World u proizvodnju. Naša aplikacija obično ide u bazu podataka ili negdje drugdje i većinu vremena čeka odgovor.

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

On samo sjedi i čeka. Nije baš dobro. Kada dođe 100.000 korisnika, nama je jako teško. Zato koristimo jednostavnu aplikaciju kao primjer. Tražit ćemo slike, na primjer, mačaka. Ali nećemo samo pretraživati, već ćemo proširiti ključne riječi i, ako je korisnik tražio "mačići", naći ćemo mačke, krznene mačke i tako dalje. Prvo, moramo dobiti podatke zahtjeva na pozadinu. izgleda ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Dvije linije vam omogućavaju da pokupite GET parametre, bez komplikacija. Dalje, recimo, iz baze podataka sa znakom za ključnu riječ i ekstenziju, dobivamo ove informacije pomoću običnog SQL upita. To je jednostavno. izgleda ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Povezivanje biblioteke resty.mysql, koji već imamo u kompletu. Ne moramo ništa da instaliramo, sve je spremno. Naznačavamo kako se povezati i napraviti SQL upit:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Ovdje je malo strašno, ali sve funkcionira. Ovdje je 10 granica. Izvlačimo 10 unosa, lijeni smo, ne želimo više prikazati. Zaboravio sam na ograničenje u SQL-u.

Zatim ćemo pronaći slike za sve upite. Prikupljamo gomilu zahtjeva i popunjavamo Lua tabelu pod nazivom reqs, i mi to radimo ngx.location.capture_multi.

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Svi ovi zahtjevi se šalju paralelno, a odgovori nam se vraćaju. Vrijeme rada je jednako vremenu odziva najsporijeg. Ako svi snimamo za 50 milisekundi, a poslali smo stotinu zahtjeva, onda ćemo dobiti odgovor za 50 milisekundi.

Pošto smo lijeni i ne želimo da pišemo HTTP i rukovanje keširanjem, nateraćemo NGINX da uradi sve umesto nas. Kao što ste videli, postojao je zahtev za url/fetch, evo ga:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Mi to činimo jednostavnim proxy_pass, naznačujemo gdje keširati, kako to učiniti i sve radi za nas.

Ali to nije dovoljno, još uvijek moramo dati podatke korisniku. Najjednostavnija ideja je serijalizirati sve u JSON-u, lako, u dva reda. Dajemo Content-Type, dajemo JSON.

Ali postoji jedna poteškoća: korisnik ne želi čitati JSON. Moramo privući front-end programere. Ponekad ne želimo ovo u početku. A SEO stručnjaci će reći da ako tražimo slike, onda im to nije važno. A ako im damo neki sadržaj, reći će da naše tražilice ništa ne indeksiraju.

Šta učiniti povodom toga? Naravno, korisniku ćemo dati HTML. Ručno generiranje nije comme il faut, pa želimo koristiti šablone. Za ovo postoji biblioteka lua-resty-template.

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Vjerovatno ste vidjeli tri zastrašujuća slova OPM. OpenResty dolazi sa vlastitim upraviteljem paketa, preko kojeg možete instalirati gomilu različitih modula, posebno, lua-resty-template. Ovo je jednostavan mehanizam za šablone, sličan Django šablonima. Tamo možete napisati kod i izvršiti zamjenu varijabli.

Kao rezultat, sve će izgledati otprilike ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Uzeli smo podatke i renderirali šablon, opet u dva reda. Korisnik je zadovoljan, dobio je mačke. Pošto smo proširili zahtjev, dobio je i foku za mačiće. Nikad se ne zna, možda je upravo to tražio, ali nije mogao ispravno formulirati svoj zahtjev.

Sve je super, ali mi smo u razvoju i još ne želimo to pokazati korisnicima. Uradimo autorizaciju. Da bismo to učinili, pogledajmo kako NGINX obrađuje zahtjev u OpenResty terminima:

  • prva faza - pristup, kada je korisnik tek stigao, a mi smo ga pogledali po zaglavljima, po IP adresi i drugim podacima. Možemo ga odmah prekinuti ako nam se ne sviđa. Ovo se može koristiti za autorizaciju, ili ako primimo mnogo zahtjeva, lako ih možemo prekinuti u ovoj fazi.
  • prepisati. Prepisujemo neke podatke zahtjeva.
  • sadržaj. Sadržaj isporučujemo korisniku.
  • filter zaglavlja. Zamjenjujemo zaglavlja odgovora. Ako smo koristili proxy_pass, možemo prepisati neka zaglavlja prije nego što ih damo korisniku.
  • filter tela. Možemo promijeniti tijelo.
  • log — logovanje. Možete pisati dnevnike u elasticsearch bez dodatnog sloja.

Naše ovlaštenje će izgledati otprilike ovako:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Ovo ćemo dodati onom location, koji smo opisali ranije, i tamo stavite sljedeći kod:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Gledamo da vidimo da li imamo token kolačića. Ako ne, onda tražimo autorizaciju. Korisnici su lukavi i mogu pogoditi da trebaju postaviti token kolačića. Stoga ćemo ga staviti i u Redis:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Kod za rad sa Redis-om je vrlo jednostavan i ne razlikuje se od ostalih jezika. U isto vrijeme, sav ulaz/izlaz, tu i tamo, nije blokiran. Ako pišete sinhroni kod, on radi asinhrono. Skoro kao gevent, ali dobro odrađeno.

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Uradimo samu autorizaciju:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Kažemo da moramo pročitati tijelo zahtjeva. Primamo POST argumente i provjeravamo da li su login i lozinka ispravni. Ako su netačni, tražimo autorizaciju. I ako je točan, onda napišite token u Redis:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Ne zaboravite postaviti kolačić, to se također radi u dva reda:

OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

Primjer je jednostavan i spekulativan. Naravno, nećemo praviti servis koji ljudima pokazuje mačke. Ali ko nas zna. Pa hajde da pređemo na ono što se može uraditi u proizvodnji.

  • Minimalistički backend. Ponekad trebamo izbaciti samo malo podataka u backend: negdje trebamo ubaciti datum, negdje trebamo prikazati listu, reći koliko je korisnika trenutno na stranici, priložiti brojač ili statistiku. Nešto tako malo. Neki minimalni komadi mogu se napraviti vrlo lako. Ovo će učiniti brzo, jednostavno i odlično.
  • Predobrada podataka. Ponekad želimo da ugradimo oglašavanje na našu stranicu, a primamo ga pomoću API zahtjeva. Ovo je vrlo lako uraditi ovdje. Ne učitavamo naš backend koji već sjedi i naporno radi. Možete ga preuzeti i preuzeti ovdje. Možemo spojiti neki JS ili, obrnuto, odvojiti ga i prethodno obraditi nešto prije nego što ga damo korisniku.
  • Fasada za mikroservis. Ovo je također jako dobar slučaj, implementirao sam ga. Prije toga radio sam u Tenzoru, firmi koja se bavi elektronskim izvještavanjem i dostavlja izvještaje otprilike polovini pravnih lica u zemlji. Napravili smo servis, mnoge stvari su tamo rađene koristeći isti mehanizam: rutiranje, autorizacija i drugo.
    OpenResty se može koristiti kao ljepilo za vaše mikroservise, pružajući jedinstven pristup svemu i jedno sučelje. Pošto se mikroservis može napisati na takav način da imate Node.js ovdje, PHP ovdje, Python ovdje, nešto Erlang ovdje, razumijemo da ne želimo da prepisujemo isti kod svuda. Stoga se OpenResty može priključiti na prednju stranu.

  • Statistika i analitika. Obično je NGINX na ulazu i svi zahtjevi prolaze kroz njega. Na ovom mjestu je vrlo zgodno sakupljati. Možete odmah nešto izračunati i otpremiti negdje, na primjer, Elasticsearch, Logstash, ili jednostavno to zapisati u dnevnik i onda poslati negdje.
  • Višekorisnički sistemi. Na primjer, online igrice su također vrlo dobre za pravljenje. Danas u Cape Townu, Alexander Gladysh će govoriti o tome kako brzo napraviti prototip igre za više igrača koristeći OpenResty.
  • Filtriranje zahtjeva (WAF). Danas je moderno praviti sve vrste zaštitnih zidova za web aplikacije; postoje mnoge usluge koje ih pružaju. Koristeći OpenResty, možete sebi napraviti zaštitni zid za web aplikacije koji će jednostavno i lako filtrirati zahtjeve prema vašim zahtjevima. Ako imate Python, onda razumete da PHP definitivno neće biti ubačen u vas, osim ako ga, naravno, ne pokrenete bilo gde sa konzole. Znate da imate MySQL i Python. Vjerovatno bi mogli pokušati napraviti neku vrstu obilaska direktorija i ubaciti nešto u bazu podataka. Stoga možete brzo i jeftino filtrirati čudne upite odmah na početku.
  • Zajednica. Pošto je OpenResty izgrađen na NGINX-u, ima bonus - ovo NGINX zajednica. Veoma je velik i pristojan dio pitanja koja ćete imati na početku već je riješila NGINX zajednica.

    Lua programeri. Jučer sam pričao sa momcima koji su došli na HighLoad++ trening dan i čuli da je samo Tarantool napisan na Lua. Ovo nije istina, puno stvari je napisano na Lui. Primeri: OpenResty, Prosody XMPP server, Love2D game engine, Lua skriptovana u Warcraft-u i drugde. Postoji mnogo Lua programera, oni imaju veliku zajednicu koja odgovara. Sva moja Lua pitanja su riješena u roku od nekoliko sati. Kada pišete na mailing listu, bukvalno u roku od nekoliko minuta već postoji gomila odgovora koji opisuju šta i kako, šta je šta. to je super. Nažalost, takva ljubazna, duhovna zajednica nije svugdje.
    Postoji GitHub za OpenResty, gdje možete otvoriti problem ako je nešto pokvareno. Postoji mailing lista na Google grupama, gdje možete razgovarati o općim pitanjima, postoji mailing lista na kineskom - nikad se ne zna, možda ne govorite engleski, ali znate kineski.

Ishodi

  • Nadam se da sam uspeo da prenesem da je OpenResty veoma zgodan okvir skrojen za web.
  • Ima nisku barijeru za ulazak, budući da je kod sličan onome na kojem pišemo, jezik je prilično jednostavan i minimalistički.
  • Pruža asinhroni I/O bez povratnih poziva, nećemo imati nikakve noodle kao što ponekad možemo napisati u NodeJS.
  • Ima laku implementaciju, jer nam je potreban samo NGINX sa potrebnim modulom i našim kodom, i sve radi odmah.
  • Velika i odgovorna zajednica.

Nisam detaljno govorio kako se radi rutiranje, ispostavilo se da je to bila jako duga priča.

Spasibo za vnimanie!


Vladimir Protasov - OpenResty: pretvaranje NGINX-a u punopravni server aplikacija

izvor: www.habr.com

Dodajte komentar