OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserverVi publiserer igjen transkripsjonen av foredraget fra konferansen HighLoad++ 2016, som fant sted i Skolkovo utenfor Moskva 7-8. november i fjor. Vladimir Protasov snakker om hvordan man kan utvide funksjonaliteten til NGINX ved hjelp av OpenResty og Lua.

Hei alle sammen, jeg heter Vladimir Protasov, og jeg jobber i Parallels. Jeg vil fortelle litt om meg selv. I tre fjerdedeler av livet mitt har jeg drevet med koding. Jeg ble programmerer til beinet, i ordets rette forstand: noen ganger drÞmmer jeg om kode. Den siste fjerdedelen av livet er industriell utvikling, skriving av kode som gÄr direkte i produksjon. Koden som noen av dere bruker, men som dere ikke er klar over.

For Ă„ gi dere et inntrykk av hvor dĂ„rlig det var. Da jeg var en ung junior, kom jeg inn i selskapet, og de ga meg sĂ„nne to terabyte databaser. Det er nĂ„ alle her har highload. Jeg var pĂ„ konferanser, spurte: «Hei, fortell meg, har dere big data, er det kult? Hvor mye har dere i databasene?» De svarte: «Vi har 100 gigabyte!» Jeg sa: «Kult, 100 gigabyte!» Men tenkte for meg selv, hvordan jeg skulle beholde pokerfjeset. Du tenker, ja, disse folkene er kule, og sĂ„ gĂ„r du tilbake og sysler med disse multi-terabyte databasene. Og dette varer — det er Ă„ vĂŠre junior. Kan dere forestille dere hvilket slag det er?

Jeg kan mer enn 20 programmeringssprÄk. Det er noe jeg mÄtte lÊre meg underveis i jobben. Du fÄr kode i Erlang, C, C++, Lua, Python, Ruby, og noe annet, og sÄ mÄ du bare jobbe med det. Det var nÞdvendig. Det eksakte antallet ble jeg ikke i stand til Ä telle, men jeg mistet tellingen etter 20.

Siden alle tilstedevÊrende vet hva Parallels er, og hva vi gjÞr, skal jeg ikke gÄ inn pÄ hvor kule vi er eller hva vi gjÞr. Jeg vil bare si at vi har 13 kontorer over hele verden, mer enn 300 ansatte, utvikling i Moskva, Tallinn, og pÄ Malta. Hvis Þnskelig kan du faktisk flytte til Malta hvis det er kaldt om vinteren og du trenger Ä varme ryggen.

VĂ„r avdeling skriver konkret i Python 2. Vi driver med virksomhet, og vi har ikke tid til Ă„ implementere trendy teknologier, sĂ„ vi lider. Vi bruker Django fordi den har alt, og vi kastet det unĂždvendige. OgsĂ„ MySQL, Redis, og NGINX. I tillegg har vi mange andre kule ting. Vi har MongoDB, vi har kaniner som lĂžper rundt, vi har sĂ„ mye rart — men det er ikke mitt ansvar, og jeg driver ikke med det.

OpenResty

Jeg har snakket om meg selv. La oss finne ut hva jeg skal snakke om i dag:

  • Hva er OpenResty og hva kan man bruke det til?
  • Hvorfor oppfinne et nytt hjul nĂ„r vi allerede har Python, NodeJS, PHP, Go og andre kule ting som alle er fornĂžyde med?
  • Og noen eksempler fra virkeligheten. Jeg mĂ„tte kutte kraftig ned pĂ„ presentasjonen min fordi den ble pĂ„ 3,5 timer, sĂ„ derfor vil det bli fĂ„ eksempler.

OpenResty er NGINX. Takket vÊre det har vi en fullt fungerende webserver som er godt skrevet og fungerer raskt. Jeg tror de fleste av oss bruker NGINX i produksjon. Alle vet at den er rask og fantastisk. Den har en imponerende synkron inn/-utdata, sÄ vi trenger ikke Ä finne opp kruttet pÄ nytt som i Python med gevent. Gevent er fantastisk, men hvis du skriver C-kode, og noe gÄr galt, kan du bli gal av Ä debugge det med gevent. Jeg har erfaring: det tok meg hele to dager Ä finne ut hva som gikk galt. Hvis noen ikke hadde gravd i det i flere uker, ikke funnet problemet, ikke skrevet om det pÄ nettet, og Google ikke hadde funnet det, hadde vi blitt sprÞ.

I NGINX er caching og statisk innhold allerede implementert. Du trenger ikke Ă„ bekymre deg for hvordan du kan gjĂžre dette pĂ„ en ordentlig mĂ„te, slik at det ikke henger seg opp noe sted, eller at du mister filbeskrivere. NGINX er veldig lett Ă„ deployere, du trenger ikke Ă„ tenke pĂ„ hva du skal bruke – WSGI, PHP-FPM, Gunicorn, Unicorn. Du installerer NGINX, gir det til administratorene, de vet hvordan de skal hĂ„ndtere det. NGINX behandler forespĂžrslene strukturert. Jeg skal si litt mer om dette senere. Kort sagt, den har en fase der den nettopp har mottatt forespĂžrselen, en fase der den har behandlet den, og en fase der den leverer innholdet til brukeren.

NGINX er flott, men det er ett problem: den er ikke fleksibel nok, selv med alle de kule funksjonene som folk har puttet inn i konfigurasjonen, til tross for at den kan konfigureres. Denne kraften er ikke tilstrekkelig. Derfor bygde folk fra Taobao for mange Är siden, omtrent Ätte Är siden, Lua inn i den. Hva gir det?

  • StĂžrrelse. Den er liten. LuaJIT gir omtrent 100-200 kilobyte overhead i minne og minimal overhead i ytelse.
  • Hastighet. LuaJIT-tolkeren er i mange situasjoner nĂŠrt C, i noen situasjoner taper den mot Java, og i andre overgĂ„r den den. En stund ble den ansett som state of the art, den mest imponerende JIT-kompilatoren. NĂ„ finnes det mer imponerende, men de er veldig tunge, som for eksempel V8. Noen JavaScript-tolker og Java HotSpot kan vĂŠre raskere i enkelte tilfeller, men i andre tilfeller taper de fortsatt.
  • Enkel Ă„ lĂŠre. Hvis du har et kodebase i Perl, og du ikke er Booking, vil du ikke finne Perl-programmerere. Fordi de ikke finnes; de har blitt alle tatt, og det tar lang tid Ă„ lĂŠre dem. Hvis du vil ha programmerere pĂ„ noe annet, mĂ„ du kanskje ogsĂ„ lĂŠre dem pĂ„ nytt eller finne dem. NĂ„r det gjelder Lua, er det enkelt. Enhver nybegynner kan lĂŠre Lua pĂ„ tre dager. Jeg brukte omtrent to timer pĂ„ Ă„ forstĂ„ det. Etter to timer skrev jeg allerede kode i produksjon. Omtrent en uke senere var det allerede i produksjon.

Som et resultat ser det slik ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Det er mye her. I OpenResty har de samlet en haug med moduler, bĂ„de Lua-baserte og engine-moduler. Og alt er klart — jeg har deployert det, og det fungerer.

Eksempler

Nok med lyrikk, la oss gÄ til koden. Her er en liten Hello World:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Hva er her? Dette er en engine-lokasjon. Vi bryr oss ikke, vi skriver ikke vĂ„r egen routing, vi tar ikke noe klart — vi har allerede det i NGINX, vi lever godt og lat.

content_by_lua_block – dette er en blokk som sier at vi leverer innhold ved hjelp av et Lua-skript. Vi tar engine-variabelen remote_addr og setter den inn i string.format. Det er det samme som sprintf, bare pĂ„ Lua, bare riktig. Og vi gir det til klienten.

Som et resultat vil det se slik ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Men la oss gÄ tilbake til den virkelige verden. I produksjon deployerer ingen Hello World. Vanligvis gÄr applikasjonen vÄr til en database eller et annet sted, og store deler av tiden venter vi pÄ respons.

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Den sitter bare og venter. Dette er ikke sÄ bra. NÄr 100.000 brukere kommer inn, er det veldig tungt for oss. SÄ la oss for eksempelets del lage en enkel applikasjon for Ä sÞke etter bilder, for eksempel katter. Men vi skal ikke bare sÞke som det; vi vil utvide nÞkkelordene, og hvis brukeren har sÞkt etter «kattunger», skal vi finne katter, fluffy osv. For Ä begynne med, mÄ vi hente forespÞrseldataene pÄ backend. Slik ser det ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

To linjer lar deg hente GET-parametere, ingen problemer. Deretter fÄr vi informasjonen fra databasen med en tabell for nÞkkelord og utvidelser via en vanlig SQL-forespÞrsel. Alt er enkelt. Slik ser det ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi kobler til biblioteket resty.mysql, som vi allerede har i pakken. Vi trenger ikke Ă„ installere noe; alt er klart. Vi spesifiserer hvordan vi skal koble til og lager SQL-forespĂžrselen:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Det er litt skummelt her, men alt fungerer. Her er 10 - det er grensen. Vi henter 10 oppfĂžringer, vi er late og Ăžnsker ikke Ă„ vise mer. Jeg glemte Ă„ nevne grensen i SQL.

Videre finner vi bilder basert pÄ alle forespÞrslene. Vi samler en bunke forespÞrsel og fyller en Lua-tabell som heter reqs, og gjÞr ngx.location.capture_multi.

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Alle disse forespÞrslene gÄr parallelt, og vi fÄr svar tilbake. Behandlingstiden er lik tiden til det langsomste svaret. Hvis vi fÄr alle svarene innen 50 millisekunder, og vi sendte ut hundre forespÞrsel, da kommer svaret vÄrt etter 50 millisekunder.

Siden vi er late og ikke Þnsker Ä skrive HTTP-behandling og caching, lar vi NGINX gjÞre alt dette for oss. Som du sÄ, var det en forespÞrsel til url/fetch, her er den:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi gjĂžr en enkel proxy_pass, angir hvor vi skal cache, hvordan vi skal gjĂžre det, og da fungerer alt.

Men dette er ikke nok, vi mÄ ogsÄ gi data til brukeren. Den enkleste ideen er Ä serialisere alt i JSON, enkelt, pÄ to linjer. Vi sender Content-Type og sender JSON.

Men det er en komplikasjon: brukeren Þnsker ikke Ä lese JSON. Vi mÄ tilkalle frontend-utviklere. Av og til vil vi ikke gjÞre dette i starten. Og SEO-ekspertene vil si at hvis vi leter etter bilder, er det dem uansett. Men hvis vi gir dem noe innhold, vil de si at sÞkemotorene ikke indekserer noe.

Hva skal vi gjĂžre med dette? SelvfĂžlgelig vil vi gi brukeren HTML. Å generere det manuelt er ikke bra, sĂ„ vi vil bruke maler. For dette har vi biblioteket lua-resty-template.

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Du sÄ kanskje de tre skumle bokstavene OPM. OpenResty kommer med sin egen pakkebehandler, gjennom hvilken du kan installere en rekke forskjellige moduler, spesielt lua-resty-template. Dette er en enkel malmotor, nÊrt relatert til Django-maler. Der kan du skrive kode og gjÞre variabel-substitusjon.

Som et resultat vil alt se omtrent slik ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi hentet data og rendrete malen i to linjer. Brukeren er glad, han fikk katter. Siden vi utvidet forespÞrselen, fikk han ogsÄ en sjÞlÞve i tillegg til kattungene. Kanskje han egentlig lette etter den, men kunne ikke formulere forespÞrselen sin riktig.

Alt er flott, men vi er jo i utviklingen, og Þnsker ikke Ä vise dette til brukerne ennÄ. La oss sette opp autentisering. For Ä gjÞre dette, la oss se hvordan NGINX behandler forespÞrselen i forhold til OpenResty:

  • Den fĂžrste fasen - access, nĂ„r brukeren nettopp har kommet, og vi ser pĂ„ ham gjennom overskriftene, IP-adressen, og annen informasjon. Vi kan umiddelbart kutte ham av hvis vi ikke liker ham. Dette kan brukes til autentisering, eller hvis vi fĂ„r for mange forespĂžrsel, kan vi enkelt kutte dem i denne fasen.
  • gjen skrive. Vi gjen skriver noen forespĂžrsel data.
  • content. Vi gir innholdet til brukeren.
  • overskrifter filter. Vi kan endre overskriftene i svaret. Hvis vi har brukt proxy_pass, kan vi omskrive noen overskrifter fĂžr vi gir dem til brukeren.
  • kropp filter. Vi kan endre kroppen.
  • log — logging. Vi kan skrive logger til elasticsearch uten et ekstra lag.

VÄr autentisering vil se omtrent slik ut:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi legger dette til den plassering, som vi beskrev tidligere, og putter inn fĂžlgende kode:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi sjekker om vi har en cookie token. Hvis ikke, sender vi til autentisering. Brukerne er smarte og kan gjette at de mÄ sette en cookie token. Derfor legger vi den ogsÄ i Redis:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Koden for Ä arbeide med Redis er veldig enkel og skiller seg ikke fra andre sprÄk. I tillegg er all input/output der, som her, ikke blokkering. Hvis du skriver synkron kode, fungerer det asynkront. Omtrent som med gevent, men det er gjort bedre.

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

La oss lage selve autentiseringen:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Vi sier at vi trenger Ä lese kroppen i forespÞrselen. Vi fÄr POST-argumentene, sjekker om brukernavnet og passordet er riktige. Hvis de ikke er riktige, sender vi til autentisering. Og hvis de er riktige, registrerer vi token i Redis:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Ikke glem Ä sette cookie, dette gjÞres ogsÄ i to linjer:

OpenResty: gjĂžr NGINX til en fullverdig applikasjonsserver

Et enkelt, hypotetisk eksempel. Vi kommer selvfÞlgelig ikke til Ä lage en tjeneste som viser folk katter. Men hvem vet. SÄ la oss se pÄ hva vi kan gjÞre i produksjon.

  • Minimalistisk backend. Av og til trenger vi Ă„ gi backend bare litt data: noen ganger mĂ„ vi sette inn en dato, vise en liste, si hvor mange brukere som er pĂ„ nettstedet, legge til en teller eller statistikk. Noe lite som det. Minimumsdelene kan lager veldig enkelt. Dette vil gĂ„ raskt, lett og bra.
  • Forbehandling av data. Noen ganger Ăžnsker vi Ă„ integrere annonser pĂ„ siden vĂ„r, og vi henter disse annonsene via API-forespĂžrslene. Dette er veldig enkelt Ă„ gjĂžre her. Vi laster ikke ned serveren vĂ„r, som allerede jobber hardt. Vi kan ta tak i og samle alt her. Vi kan lage noen JS-moduler eller, omvendt, splitte opp og preprocessere noe fĂžr vi leverer det til brukeren.
  • Grensesnitt for mikrotjenester. Dette er ogsĂ„ et veldig godt case, jeg har implementert det. FĂžr dette jobbet jeg i selskapet Tenzor, som driver med elektronisk rapportering og tar seg av rapporteringen for omtrent halvparten av juridiske enheter i landet. Vi lagde en tjeneste hvor mange funksjoner ble realisert med samme mekanisme: ruting, autorisasjon og mer.
    OpenResty kan brukes som lim for mikrotjenestene dine, noe som gir enhetlig tilgang til alt og et enhetlig grensesnitt. Siden mikrotjenester kan vÊre skrevet i forskjellige sprÄk som Node.js, PHP, Python, og noe som kjÞrer pÄ Erlang, forstÄr vi at vi ikke Þnsker Ä skrive den samme koden overalt. Derfor kan OpenResty settes opp pÄ frontenden.
  • Statistikk og analyse. Vanligvis stĂ„r NGINX foran, og alle forespĂžrslene gĂ„r gjennom det. Her er det veldig praktisk Ă„ samle data. Man kan umiddelbart utfĂžre beregninger og sende dem et sted, for eksempel til Elasticsearch, Logstash eller bare skrive dem til logg for senere sending.
  • Flerebrukersystemer. For eksempel er det ogsĂ„ veldig bra Ă„ lage online-spill. I dag vil Alexander Gladys i Cape Town snakke om hvordan man raskt kan prototype et flerebrukerspill ved hjelp av OpenResty.
  • ForespĂžrsel filtrering (WAF). NĂ„ er det populĂŠrt Ă„ lage diverse webapplikasjonsbrannmurer, og det finnes mange tjenester som tilbyr dem. Med OpenResty kan man lage sin egen webapplikasjonsbrannmur som enkelt og greit kan filtrere forespĂžrslene etter dine krav. Hvis du jobber med Python, vet du at PHP antageligvis ikke kan injiseres, med mindre du spawner det fra konsollen. Du vet at du har MySQL og Python, sĂ„ kanskje noen prĂžver Ă„ utfĂžre directory traversal og injisere noe i databasen. Derfor kan man raskt og kostnadseffektivt filtrere uĂžnskede forespĂžrslene pĂ„ frontenden.
  • Fellesskapet. Siden OpenResty er bygget pĂ„ NGINX, har det en bonus - det er NGINX-fellesskapetDet er veldig stort, og en betydelig del av spĂžrsmĂ„lene du mĂ„tte ha i starten, er allerede lĂžst av NGINX-samfunnet.

    Lua-utviklereI gÄr snakket jeg med folk som kom til HighLoad++ lÊringsdagen og hÞrte at det kun er Tarantool skrevet i Lua. Det er ikke sant, det er mye skrevet i Lua. Eksempler: OpenResty, XMPP-serveren Prosody, spillmotoren Love2D, Lua skriptes i Warcraft og andre steder. Det er mange Lua-utviklere, og de har et stort og hjelpsomt fellesskap. Alle mine spÞrsmÄl om Lua ble lÞst i lÞpet av noen timer. NÄr man skriver til e-postlisten, fÄr man bokstavelig talt en haug med svar innen minutter, de forklarer hva og hvordan, hva som gjelder. Det er veldig flott. Dessverre er ikke alle slike vennlige sjeler.
    Det finnes et GitHub for OpenResty, der kan man opprette en issue hvis noe er Þdelagt. Det finnes en e-postliste pÄ Google Groups hvor man kan diskutere generelle spÞrsmÄl, det er ogsÄ en mailingliste pÄ kinesisk - man vet aldri, kanskje man ikke behersker engelsk, men kan kinesisk.

Resultater

  • Jeg hĂ„per jeg har klart Ă„ formidle at OpenResty er et veldig praktisk rammeverk, skreddersydd for web.
  • Det har lav terskel for inntreden, siden koden ligner pĂ„ det vi skriver, sprĂ„ket er ganske enkelt og minimalistisk.
  • Det tilbyr asynkron I/O uten tilbakemeldinger, vi fĂ„r ikke spagetti som vi noen ganger kan skrive i NodeJS.
  • Det har enkel distribusjon, siden vi kun trenger NGINX med det nĂždvendige modulen og koden vĂ„r, sĂ„ fungerer alt med en gang.
  • Et stort og responsivt fellesskap.

Jeg forklarte ikke i detalj hvordan ruting gjĂžres, det ville blitt en veldig lang historie.

Takk for oppmerksomheten!

Spill video

Vladimir Protasov - OpenResty: vi forvandler NGINX til en fullverdig applikasjonsserver

Kilde: habr.com
KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KjĂžp pĂ„litelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster