Vi publiserer igjen utskriften av konferanserapporten 2016, som fant sted i Skolkovo ved Moskva 7.–8. november i fjor. forklarer hvordan du utvider NGINX-funksjonaliteten med OpenResty og Lua.
Hei alle sammen, mitt navn er Vladimir Protasov, jeg jobber på Parallels. Jeg skal fortelle deg litt om meg selv. Jeg bruker tre fjerdedeler av livet mitt på å skrive kode. Jeg ble en programmerer til kjernen i bokstavelig forstand: noen ganger ser jeg kode i drømmene mine. En fjerdedel av livet er industriell utvikling, skriving av kode som går rett i produksjon. En kode som noen av dere bruker, men som ikke er klar over det.
Så du skjønner hvor ille det var. Da jeg var liten kom jeg og fikk disse to terabyte databasene. Det er høy belastning for alle her nå. Jeg dro på konferanser og spurte: «Gutter, si meg, dere har store data, er alt kult? Hvor mange baser har du der? De svarte meg: "Vi har 100 gigabyte!" Jeg sa: "Kult, 100 gigabyte!" Og jeg tenkte med meg selv hvordan jeg skulle vedlikeholde pokeransiktet mitt nøye. Du tror, ja, gutta er kule, og så går du tilbake og pirker med disse multi-terabyte-databasene. Og dette er å være junior. Kan du forestille deg hvilket slag dette er?
Jeg kan mer enn 20 programmeringsspråk. Dette er noe jeg måtte finne ut av mens jeg jobbet. De gir deg kode i Erlang, C, C++, Lua, Python, Ruby, noe annet, og du må kutte alt. Generelt måtte jeg det. Det var ikke mulig å beregne det nøyaktige tallet, men et sted rundt den 20. gikk tallet tapt.
Siden alle tilstedeværende vet hva Parallels er og hva vi gjør, vil jeg ikke snakke om hvor kule vi er og hva vi gjør. Jeg skal bare fortelle deg at vi har 13 kontorer rundt om i verden, mer enn 300 ansatte, utvikling i Moskva, Tallinn og Malta. Hvis du ønsker, kan du ta den og flytte til Malta hvis det er kaldt om vinteren og du trenger å varme opp ryggen.
Nærmere bestemt skriver vår avdeling i Python 2. Vi er i virksomhet og har ikke tid til å implementere fasjonable teknologier, så vi lider. Vi bruker Django fordi den har alt, og vi tok det som var unødvendig og kastet det. Også MySQL, Redis og NGINX. Vi har også mye annet kult. Vi har MongoDB, vi har kaniner som løper rundt, vi har alt – men det er ikke mitt, og jeg gjør det ikke.
OpenResty
Jeg fortalte om meg selv. La oss finne ut hva jeg skal snakke om i dag:
- Hva er OpenResty og hva spises det med?
- Hvorfor finne opp enda et hjul når vi har Python, NodeJS, PHP, Go og andre kule ting som alle er fornøyde med?
- Og noen få eksempler fra livet. Jeg måtte kutte ned praten mye fordi den var 3,5 timer lang, så det blir ikke mange eksempler.
OpenResty er NGINX. Takket være ham har vi en fullverdig webserver som er velskrevet og fungerer raskt. Jeg tror de fleste av oss bruker NGINX i produksjonen. Dere vet alle at han er rask og kul. De laget kule synkron I/O i den, så vi trenger ikke å sykle noe, akkurat som de gjorde i Python. Gevent er kult, flott, men hvis du skriver C-kode og noe går galt, vil du med Gevent bli gal av å feilsøke den. Jeg hadde erfaringen: det tok to hele dager å finne ut hva som gikk galt der. Hvis noen ikke hadde gravd rundt på flere uker, funnet problemet, skrevet på Internett, og Google ikke hadde funnet det, så hadde vi blitt helt gale.
NGINX har allerede caching og statisk innhold gjort. Du trenger ikke bekymre deg for hvordan du gjør dette menneskelig, slik at du ikke senker farten et sted, slik at du ikke mister beskrivelser et sted. Nginx er veldig praktisk å distribuere, du trenger ikke tenke på hva du skal ta - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx ble installert, gitt til administratorene, de vet hvordan de skal jobbe med det. Nginx behandler forespørsler på en strukturert måte. Jeg skal snakke om dette litt senere. Kort sagt, den har en fase da den nettopp godtok forespørselen, når den behandlet den, og når den serverte innholdet til brukeren.
Nginx er kult, men det er ett problem: det er ikke fleksibelt nok, selv med alle de kule funksjonene som gutta har stappet inn i konfigurasjonen, til tross for hva som kan konfigureres. Denne kraften er ikke nok. Det er grunnen til at gutta fra Taobao, for lenge siden, virker som åtte år siden, bygde Lua inn i den. Hva gir det?
- Størrelse. Det er lite. LuaJIT gir omtrent 100-200 kilobyte med minneoverhead og minimal ytelsesoverhead.
- Fart. LuaJIT-tolken er nær C i mange situasjoner, i noen situasjoner taper den mot Java, og i andre utkonkurrerer den. I noen tid ble det ansett som toppmoderne, den kuleste JIT-kompilatoren. Nå er det kulere, men de er veldig tunge, for eksempel samme V8. Noen JS-tolker og Java HotSpot er raskere på noen punkter, men noen steder taper de fortsatt.
- Lett å lære. Hvis du for eksempel har en Perl-kodebase, og du ikke booker, vil du ikke finne Perl-programmerere. Fordi de ikke eksisterer, ble de alle tatt bort, og å lære dem er langt og vanskelig. Hvis du vil ha programmerere til noe annet, må du kanskje også omskolere dem eller finne dem. Når det gjelder Lua, er alt enkelt. Enhver junior kan lære Lua på tre dager. Det tok meg omtrent to timer å finne ut av det. To timer senere skrev jeg allerede kode i produksjon. Omtrent en uke senere gikk han rett til produksjon og dro.
Som et resultat ser det slik ut:

Det er mye her. OpenResty har samlet en haug med moduler, både luash og motor. Og du har alt klart - utplassert og fungerer.
Примеры
Nok av tekstene, la oss gå videre til koden. Her er en liten Hello World:

Hva er der? Dette er et Engins-sted. Vi bekymrer oss ikke, vi skriver ikke vår egen ruting, vi tar ikke en ferdig - vi har den allerede i NGINX, vi lever et godt og lat liv.
content_by_lua_block er en blokk som sier at vi serverer innhold ved hjelp av et Lua-skript. Vi tar Engines-variabelen remote_addr og legg den inn string.format. Det er det samme som sprintf, bare i Lua, bare riktig. Og vi gir det til kunden.
Som et resultat vil det se slik ut:

Men la oss gå tilbake til den virkelige verden. Ingen distribuerer Hello World til produksjon. Vår applikasjon går vanligvis til databasen eller et annet sted, og mesteparten av tiden venter på svar.

Han bare sitter og venter. Det er ikke veldig bra. Når 100.000 XNUMX brukere kommer, er det veldig vanskelig for oss. Så la oss bruke en enkel applikasjon som eksempel. Vi skal se etter bilder, for eksempel av katter. Men vi vil ikke bare søke, vi utvider søkeordene, og hvis brukeren søkte etter "kattunger", vil vi finne katter, lodne katter og så videre. Først må vi få forespørselsdataene på backend. Det ser slik ut:

To linjer lar deg plukke opp GET-parametere, ingen komplikasjoner. Deretter, la oss si, fra en database med et tegn for et nøkkelord og utvidelse, henter vi denne informasjonen ved å bruke en vanlig SQL-spørring. Det er enkelt. Det ser slik ut:

Koble til biblioteket resty.mysql, som vi allerede har i settet. Vi trenger ikke installere noe, alt er klart. Vi angir hvordan du kobler til og lager en SQL-spørring:

Det er litt skummelt her, men alt fungerer. Her er 10 grensen. Vi trekker ut 10 bidrag, vi er late, vi vil ikke vise flere. Jeg glemte grensen i SQL.
Deretter finner vi bilder for alle spørsmål. Vi samler en haug med forespørsler og fyller ut en Lua-tabell som heter reqs, og det gjør vi ngx.location.capture_multi.

Alle disse forespørslene sendes parallelt, og svar returneres til oss. Driftstiden er lik responstiden til den tregeste. Hvis vi alle skyter på 50 millisekunder, og vi sendte hundre forespørsler, vil vi få svar om 50 millisekunder.
Siden vi er late og ikke ønsker å skrive HTTP og caching-håndtering, får vi NGINX til å gjøre alt for oss. Som du så, var det en forespørsel om url/fetch, her er han:

Vi gjør det enkelt proxy_pass, angir vi hvor vi skal bufre, hvordan du gjør det, og alt fungerer for oss.
Men dette er ikke nok, vi må fortsatt gi dataene til brukeren. Den enkleste ideen er å serialisere alt i JSON, enkelt, i to linjer. Vi gir Content-Type, vi gir JSON.
Men det er en vanskelighet: brukeren vil ikke lese JSON. Vi må tiltrekke oss front-end utviklere. Noen ganger ønsker vi ikke å gjøre dette med det første. Og SEO-spesialister vil si at hvis vi leter etter bilder, så spiller det ingen rolle for dem. Og hvis vi gir dem noe innhold, vil de si at søkemotorene våre ikke indekserer noe.
Hva skal man gjøre med det? Selvfølgelig vil vi gi brukeren HTML. Å generere for hånd er ikke comme il faut, så vi ønsker å bruke maler. Det er et bibliotek for dette lua-resty-template.

Du har sikkert sett de tre skumle bokstavene OPM. OpenResty kommer med sin egen pakkebehandling, der du kan installere en haug med forskjellige moduler, spesielt, lua-resty-template. Dette er en enkel malmotor, som ligner på Django-maler. Der kan du skrive kode og utføre variabelsubstitusjon.
Som et resultat vil alt se omtrent slik ut:

Vi tok dataene og gjengav malen, igjen på to linjer. Brukeren er fornøyd, han fikk katter. Siden vi utvidet forespørselen, fikk han også en pelssel til kattunger. Du vet aldri, kanskje han var ute etter akkurat dette, men kunne ikke formulere forespørselen sin riktig.
Alt er kult, men vi er i utvikling og ønsker ikke å vise det til brukerne ennå. La oss gjøre autorisasjonen. For å gjøre dette, la oss se på hvordan NGINX håndterer forespørselen i OpenResty-vilkår:
- Den første fasen er adgang, da brukeren nettopp kom, og vi så på ham etter overskrifter, etter IP-adresse og andre data. Vi kan umiddelbart kutte det hvis vi ikke liker det. Dette kan brukes til autorisasjon, eller hvis vi mottar mange forespørsler, kan vi enkelt kutte dem i denne fasen.
- omskrive. Vi omskriver noen forespørselsdata.
- innhold. Vi leverer innholdet til brukeren.
- overskrifter filter. Vi bytter ut svarhodene. Hvis vi brukte
proxy_pass, kan vi skrive om noen overskrifter før vi gir den til brukeren. - kroppsfilter. Vi kan forandre kroppen.
- logg - hogst. Du kan skrive logger i elasticsearch uten et ekstra lag.
Vår autorisasjon vil se omtrent slik ut:

Vi legger dette til den location, som vi beskrev før, og satte følgende kode der:

Vi ser for å se om vi har en cookie-token. Hvis ikke, ber vi om autorisasjon. Brukere er utspekulerte og kan gjette at de må angi et informasjonskapseltoken. Derfor vil vi også legge det i Redis:

Koden for å jobbe med Redis er veldig enkel og er ikke forskjellig fra andre språk. Samtidig blokkerer ikke all input/output, her og der. Hvis du skriver synkron kode, fungerer den asynkront. Nesten som gavt, men gjort bra.

La oss gjøre autorisasjonen selv:

Vi sier at vi må lese innholdet i forespørselen. Vi mottar POST-argumenter og sjekker at innlogging og passord er riktig. Hvis de er feil, utfordrer vi deg om autorisasjon. Og hvis riktig, så skriv tokenet i Redis:

Ikke glem å sette informasjonskapselen, dette gjøres også på to linjer:

Eksemplet er enkelt og spekulativt. Vi skal selvfølgelig ikke lage en tjeneste som viser folk katter. Men hvem kjenner oss. Så la oss gå over hva som kan gjøres i produksjonen.
- Minimalistisk backend. Noen ganger må vi bare sende ut litt data til backend: et sted må vi sette inn en dato, et sted må vi vise en liste, si hvor mange brukere som er på siden nå, legge ved en teller eller statistikk. Noe så lite. Noen minimale stykker kan lages veldig enkelt. Dette vil gjøre det raskt, enkelt og flott.
- Dataforbehandling. Noen ganger ønsker vi å bygge inn reklame på siden vår, og vi mottar denne reklamen ved å bruke API-forespørsler. Dette er veldig enkelt å gjøre her. Vi laster ikke backend vår, som allerede sitter og jobber hardt. Du kan hente den og hente den her. Vi kan flette sammen noen JS eller omvendt, koble den fra og forbehandle noe før vi gir den til brukeren.
- Fasade for mikroservice. Dette er også en veldig god sak, jeg implementerte den. Før det jobbet jeg i Tenzor, et selskap som driver med elektronisk rapportering og gir rapportering til omtrent halvparten av de juridiske enhetene i landet. Vi opprettet en tjeneste, mange ting ble gjort der ved å bruke samme mekanisme: ruting, autorisasjon og mer.
OpenResty kan brukes som limet for mikrotjenestene dine, og gir en enkelt tilgang til alt og et enkelt grensesnitt. Siden mikrotjenester kan skrives på en slik måte at du har Node.js her, PHP her, Python her, noe Erlang-ting her, forstår vi at vi ikke ønsker å omskrive den samme koden overalt. Derfor kan OpenResty kobles til fronten. - Statistikk og analyser. Vanligvis er NGINX ved inngangen, og alle forespørsler går gjennom den. Det er på dette stedet det er veldig praktisk å samle. Du kan umiddelbart beregne noe og laste det opp et sted, for eksempel Elasticsearch, Logstash, eller bare skrive det til loggen og deretter sende det et sted.
- Flerbrukersystemer. Nettspill er for eksempel også veldig gode å lage. I dag i Cape Town vil Alexander Gladysh snakke om hvordan man raskt kan prototyper et flerspillerspill ved hjelp av OpenResty.
- Forespørselsfiltrering (WAF). I dag er det mote å lage alle slags brannmurer for nettapplikasjoner; det er mange tjenester som tilbyr dem. Ved å bruke OpenResty kan du lage deg selv en nettapplikasjonsbrannmur som enkelt og enkelt vil filtrere forespørsler i henhold til dine krav. Hvis du har Python, så forstår du at PHP definitivt ikke vil bli injisert i deg, med mindre du selvfølgelig spawner det hvor som helst fra konsollen. Du vet at du har MySQL og Python. Sannsynligvis kan de prøve å gjøre en slags kataloggjennomgang og injisere noe i databasen. Derfor kan du filtrere ut rare søk raskt og billig rett foran.
- Samfunnet. Siden OpenResty er bygget på NGINX, har den en bonus: NGINX fellesskap. Den er veldig stor, og en anstendig del av spørsmålene du først vil ha, har allerede blitt løst av NGINX-fellesskapet.
Lua utviklere. I går snakket jeg med gutta som kom til HighLoad++ treningsdagen og hørte at bare Tarantool var skrevet i Lua. Dette er ikke sant, mange ting er skrevet i Lua. Eksempler: OpenResty, Prosody XMPP-server, Love2D-spillmotor, Lua skriptet i Warcraft og andre steder. Det er mange Lua-utviklere, de har et stort og responsivt fellesskap. Alle mine Lua-spørsmål ble løst i løpet av noen få timer. Når du skriver til e-postlisten, er det bokstavelig talt i løpet av noen få minutter allerede en haug med svar, som beskriver hva og hvordan, hva er hva. Det er flott. Dessverre er et slikt, åndelig fellesskap ikke overalt.
Det er GitHub for OpenResty, hvor du kan åpne et problem hvis noe er ødelagt. Det er en e-postliste på Google Groups hvor du kan diskutere generelle spørsmål, det er en e-postliste på kinesisk - du vet aldri, kanskje du ikke snakker engelsk, men du kan kinesisk.
Resultater av
- Jeg håper jeg var i stand til å formidle at OpenResty er et veldig praktisk rammeverk skreddersydd for nettet.
- Den har lav inngangsbarriere, siden koden ligner på det vi skriver på, er språket ganske enkelt og minimalistisk.
- Det gir asynkron I/O uten tilbakeringing, vi vil ikke ha noen nudler som vi noen ganger kan skrive i NodeJS.
- Den har enkel distribusjon, siden vi bare trenger NGINX med den nødvendige modulen og koden vår, og alt fungerer umiddelbart.
- Stort og lydhørt fellesskap.
Jeg fortalte ikke i detalj hvordan ruting gjøres, det viste seg å være en veldig lang historie.
Takk for din oppmerksomhet!

Kilde: www.habr.com
