OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserverVi offentliggør igen transskriptionen af ​​foredraget fra konferencen HighLoad++ 2016, der fandt sted i Skolkovo i Moskva-regionen den 7.-8. november sidste år. Vladimir Protasov fortæller, hvordan man udvider funktionaliteten af NGINX med OpenResty og Lua.

Hej alle, jeg hedder Vladimir Protasov, og jeg arbejder hos Parallels. Jeg vil fortælle lidt om mig selv. Tre fjerdedele af mit liv har jeg skrevet kode. Jeg er blevet programmør ind til benet i bogstaveligste forstand: nogle gange drømmer jeg om kode. En fjerdedel af mit liv har jeg arbejdet med industriel udvikling, skrevet kode, der går direkte i produktion. Koden, som nogle af jer bruger, men ikke er klar over.

For at forstå, hvor slemt det har været. Da jeg var en lille junior, kom jeg ind, og jeg fik tildelt sådanne to terabyte databaser. Det er nu, at alle har highload her. Jeg gik til konferencer og spurgte: "Folkens, fortæl mig, har I big data, er det fedt? Hvor store er jeres databaser?" De svarede: "Vi har 100 gigabyte!" Jeg sagde: "Fedt, 100 gigabyte!" Men i mit hoved tænkte jeg, hvordan jeg forsigtigt kunne bevare pokerfjæset. Man tænker, ja, de er seje, og så vender man tilbage og roder med de mange terabyte store databaser. Og det er mens man er junior. Kan I forestille jer, hvilken slag det er?

Jeg kender mere end 20 programmeringssprog. Det er det, jeg måtte finde ud af i løbet af mit arbejde. Du får kode i Erlang, C, C++, Lua, Python, Ruby, og noget andet, og du skal arbejde med det hele. Jeg måtte bare finde ud af det. Det præcise antal kunne jeg ikke tælle, men jeg har mistet overblikket efter 20.

Da alle tilstedeværende ved, hvad Parallels er, og hvad vi laver, vil jeg ikke tale om, hvor seje vi er, og hvad vi gør. Jeg vil kun nævne, at vi har 13 kontorer rundt om i verden, over 300 ansatte, udvikling i Moskva, Tallinn og Malta. Hvis du ønsker det, kan du flytte til Malta, hvis det er koldt om vinteren, og du vil varme ryggen.

Vores afdeling skriver konkret i Python 2. Vi beskæftiger os med forretning, og vi har ikke tid til at implementere de trendy teknologier, derfor lider vi. Vi har Django, fordi alt er der, og det overskydende har vi smidt væk. Også MySQL, Redis og NGINX. Desuden har vi mange andre seje ting. Vi har MongoDB, vi har kaniner løbende rundt, vi har næsten alt – men det er ikke mit område, og jeg arbejder ikke med det.

OpenResty

Jeg har fortalt om mig selv. Lad os finde ud af, hvad jeg vil tale om i dag:

  • Hvad er OpenResty, og hvad skal man bruge det til?
  • Hvorfor opfinde endnu en cykel, når vi har Python, NodeJS, PHP, Go og andre fede ting, som alle er glade for?
  • Og lidt eksempler fra virkeligheden. Jeg måtte skære mit foredrag ned betydeligt, fordi det blev 3,5 timer langt, så der bliver ikke mange eksempler.

OpenResty er NGINX. Takket være det har vi en fuldgyldig webserver, der er godt skrevet og arbejder hurtigt. Jeg tror, de fleste af os bruger NGINX i produktion. I ved alle, at det er hurtigt og godt. Der er lavet fantastisk synkron ind- og uddata, så vi behøver ikke at genopfinde hjulet, som vi gjorde i Python med gevent. Gevent er fantastisk, men hvis du skriver noget C-kode, og der er problemer, så bliver du sindssyg af at debugge det med gevent. Jeg har erfaring med det: Det tog mig hele to dage at finde ud af, hvad der gik galt. Hvis ikke nogen havde rodet med det i flere uger, fundet problemet, skrevet om det på nettet, og Google havde fundet det, så ville vi være totalt forvirrede.

NGINX har allerede cache og statisk indhold. Du behøver ikke at bekymre dig om, hvordan man gør det ordentligt, så der ikke sker forsinkelser, og du ikke mister descriptors et eller andet sted. Nginx er meget nemt at deployere, du skal ikke tænke over, hvad du skal vælge - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx er installeret, givet til administratorerne, de ved, hvordan man arbejder med det. Nginx behandler anmodninger struktureret. Jeg vil fortælle lidt mere om det senere. Kort sagt har den en fase, når den har modtaget anmodningen, en når den har behandlet den, og en når den har sendt indholdet til brugeren.

Nginx er fedt, men der er ét problem: det er ikke fleksibelt nok, selv med alle de fede funktioner, som folk har fået presset ind i konfigurationen, på trods af at det er konfigurerbart. Denne kraft er ikke nok. Derfor indbyggede folk fra Taobao for nøjagtigt otte år siden Lua derind. Hvad giver det?

  • Størrelse. Det er lille. LuaJIT har omkring 100-200 kilobyte overhead i hukommelse og minimal overhead i ydeevne.
  • Hastighed. LuaJIT's interpreter er i mange situationer tæt på C, i nogle situationer er den langsommere end Java, og i andre situationer overgår den den. I en periode blev den betragtet som state of the art, den bedste JIT-compilator. Nu findes der bedre, men de er meget tungere, som for eksempel V8. Nogle JavaScript-interpretere og Java's HotSpot er hurtigere på nogle punkter, men på andre steder er de stadig langsommere.
  • Nemetski nedele.. Hvis du for eksempel har en kodebase i Perl, og du ikke er Booking, vil du ikke finde Perl-programmører. Fordi de ikke eksisterer, de er alle taget, og det tager lang tid at lære dem. Hvis du vil have programmører på noget andet, skal du muligvis også genuddanne dem, eller finde dem. I Lua er det enkelt. Enhver junior kan lære Lua på tre dage. Det tog mig cirka to timer at forstå det. Efter to timer skrev jeg allerede kode til produktion. Efter omtrent en uge blev det direkte sendt til produktionen.

Som resultat ser det sådan ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Der er meget her. I OpenResty har de samlet en masse moduler, både Lua og enginspecifikke. Og du har alt klar – deployet og det fungerer.

Eksempler

Lad os stoppe med lyrikken og gå videre til koden. Her er et lille Hello World:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Hvad er der her? Dette er en enginspecifik location. Vi bekymrer os ikke, skriver ikke vores egen routing, tager ikke noget eksisterende – vi har allerede det, der er i NGINX, vi lever komfortabelt og dovent.

content_by_lua_block – dette er en blok, der angiver, at vi leverer indhold via et Lua-script. Vi tager en enginspecifik variabel remote_addr og indsætter den i string.format. Dette er det samme som sprintf, kun på Lua, kun korrekt. Og vi leverer det til klienten.

Som resultat vil det se sådan ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Men lad os vende tilbage til den virkelige verden. Ingen deployer Hello World i produktion. Vores applikation går normalt til databasen eller et andet sted og venter størstedelen af tiden på et svar.

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Den sidder bare stille og venter. Det er ikke så godt. Når 100.000 brugere kommer, bliver det meget hårdt for os. Så lad os som eksempel lave en simpel applikation. Vi vil søge efter billeder, for eksempel af katte. Men vi vil ikke bare søge, vi vil udvide søgeordene, og hvis brugeren søger på 'killinger', finder vi katte, pelsede væsner og så videre. Først skal vi modtage forespørgselsdataene på backend. Det ser sådan ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

To linjer giver dig mulighed for at hente GET-parametrene, ingen komplikationer. Dernæst får vi for eksempel information fra databasen med en tabel baseret på søgeord og udvidelse via en almindelig SQL-forespørgsel. Alt er enkelt. Det ser sådan ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi tilslutter biblioteket resty.mysql, som vi allerede har i pakken. Vi behøver ikke at installere noget, alt er klar. Angiv hvordan man skal oprette forbindelse, og lav en SQL-forespørgsel:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Det er lidt skræmmende her, men det fungerer. Her er 10 - det er grænsen. Vi trækker 10 poster, vi er dovne og vil ikke vise flere. Jeg glemte at nævne grænsen i SQL.

Derefter finder vi billeder på alle forespørgsler. Vi samler en bunke forespørgsler og udfylder en Lua-tabel, som hedder reqs, og vi laver ngx.location.capture_multi.

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Alle disse forespørgsler sendes parallelt, og vi får svar tilbage. Den samlede tid er lig med responstiden for den langsomste. Hvis vi får alle svar på 50 millisekunder, og vi har sendt hundrede forespørgsler, så får vi svaret om 50 millisekunder.

Da vi er dovne og ikke ønsker at skrive HTTP-behandling og caching, vil vi lade NGINX gøre alt for os. Som du så, var der en forespørgsel til url/fetch, her er den:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi laver en enkel proxy_pass, angiver, hvor vi skal cache, hvordan vi gør det, og så virker det hele.

Men det er ikke nok, vi skal også give data til brugeren. Den enkleste idé er at serialisere alt til JSON, nemt, i to linjer. Vi sender Content-Type, vi sender JSON.

Men der er én udfordring: brugeren vil ikke læse JSON. Vi skal tiltrække front-end udviklere. Nogle gange ønsker vi ikke at gøre dette i starten. Og SEO-specialisterne siger, at hvis vi søger efter billeder, så er de ligeglade. Men hvis vi giver dem noget indhold, vil de sige, at søgemaskinerne ikke indekserer noget.

Hvad skal vi gøre ved dette? Selvfølgelig vil vi levere HTML til brugeren. At generere manuelt er ikke så smart, så vi ønsker at bruge skabeloner. Til dette formål findes der et bibliotek, lua-resty-template.

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Du har sikkert set de tre skræmmende bogstaver OPM. OpenResty kommer med sin egen pakkehåndtering, hvorigennem man kan installere en masse forskellige moduler, herunder lua-resty-template. Det er en simpel skabelonmotor, der ligner Django templates. Der kan man skrive kode og erstatte variable.

Resultatet vil se nogenlunde sådan her ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi tog dataene og rendere skabelonen igen på to linjer. Brugeren er glad, han fik katte. Da vi udvidede forespørgslen, fik han ikke kun kattekillinger, men også en søløve. Man ved aldrig, måske søgte han netop efter den, men kunne ikke formulere sin forespørgsel korrekt.

Det er fantastiskt, men vi er i udviklingen, og vil ikke vise det til brugerne endnu. Lad os lave en autorisation. For at gøre dette, lad os se på, hvordan NGINX håndterer forespørgslen i termer af OpenResty:

  • Den første fase - access, når brugeren lige er kommet, og vi har set på ham gennem overskrifterne, IP-adressen, og andre data. Vi kan straks afbryde ham, hvis vi ikke kan lide ham. Dette kan bruges til autentificering, eller hvis vi får mange forespørgsler, kan vi let afbryde dem på dette trin.
  • rewrite. Vi omskriver nogle data fra forespørgslen.
  • for indhold med billeder (alternativ tekst. Vi leverer indholdet til brugeren.
  • headers filter. Vi kan ændre svaroverskrifterne. Hvis vi har brugt proxy_pass, kan vi ændre nogle overskrifter, før vi giver dem til brugeren.
  • body filter. Vi kan ændre kroppen.
  • log — logning. Vi kan skrive logs til elasticsearch uden et ekstra lag.

Vores autentificering vil se cirka sådan ud:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi tilføjer dette i den location, som vi beskrev før, og putter sådan en kode derind:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi ser, om vi har en cookie token. Hvis ikke, sender vi dem til autentificering. Brugerne er snedige og kan gætte, at de skal sætte cookie token. Derfor lægger vi også denne i Redis:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Koden til at arbejde med Redis er meget enkel og adskiller sig ikke fra andre sprog. Samtidig er al ind- og uddata, hvad enten det er der eller her, ikke blokkerende. Hvis du skriver synkront kode, så kører det asynkront. Lidt ligesom med gevent, men gjort godt.

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Lad os lave selve autentificeringen:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Vi siger, at vi skal læse kroppens indhold. Vi får POST-argumenterne, kontrollerer, at login og password er korrekte. Hvis de er forkerte, sender vi dem til autentificering. Hvis de er korrekte, gemmer vi token i Redis:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Glem ikke at sætte cookie, det gøres også i to linjer:

OpenResty: Forvandler NGINX til en fuldgyldig applikationsserver

Eksemplet er simpelt og teoretisk. Vi vil naturligvis ikke lave en service, der viser folk katte. Men hvem ved. Lad os derfor se på, hvad der kan gøres i produktion.

  • Minimalistisk backend. Nogle gange kræver det, at backend kun leverer nogle få data: et sted skal der indsættes en dato, et andet sted skal der vises en liste, sige, hvor mange brugere der i øjeblikket er på siden, tilføje en tæller eller statistik. Noget stort. Nogle minimale stykker kan laves meget nemt. Det vil være hurtigt, nemt og godt.
  • Datapreprocessering. Nogle gange har vi lyst til at integrere reklame på vores side, og denne reklame henter vi via API-anmodninger. Det er meget nemt at gøre lige her. Vi belaster ikke vores backend, som allerede arbejder hårdt. Man kan tage og samle det her. Vi kan samle nogle JS eller omvendt, splitte noget op, eller preprocessere det, før vi sender det til brugeren.
  • Facade til mikroservice. Det er også et meget godt projekt, som jeg har implementeret. Før dette arbejdede jeg i Tenzor, som beskæftiger sig med elektronisk rapportering og leverer rapportering til cirka halvdelen af ​​juridiske personer i landet. Vi lavede en service, hvor mange funktioner blev udført ved hjælp af denne samme mekanisme: ruting, autorisation og mere.
    OpenResty kan bruges som lim til dine mikroservices, som giver en ensartet adgang til alt og et ensartet interface. Da mikroservices kan være skrevet sådan, at her har du Node.js, her har du PHP, her Python, og her står der noget på Erlang, forstår vi, at vi ikke ønsker at skulle skrive den samme kode overalt. Derfor kan OpenResty sættes på frontend.
  • Statistik og analyser. Normalt står NGINX foran, og alle anmodninger går igennem det. Det er her, det er meget praktisk at samle. Man kan straks beregne noget og sende det et sted hen, for eksempel til Elasticsearch, Logstash eller simpelthen logge det og senere sende det videre.
  • Flermandsystemer. For eksempel er det også meget godt at lave online-spil. I dag vil Alexander Gladys tale i Cape Town om, hvordan man hurtigt prototyper et flermands-spil ved hjælp af OpenResty.
  • Anmodningsfiltrering (WAF). Det er nu moderne at lave forskellige web application firewalls, der er mange tjenester, der tilbyder dem. Ved hjælp af OpenResty kan du lave din egen web application firewall, der nemt og hurtigt filtrerer anmodninger efter dine krav. Hvis du bruger Python, ved du, at PHP bestemt ikke kan injiceres, hvis du ikke spawnede det fra konsollen et eller andet sted. Du ved, at du har MySQL og Python. Måske vil nogen forsøge at lave et directory traversal og injicere noget i databasen. Derfor kan du hurtigt og billigt filtrere uønskede anmodninger direkte på frontend.
  • Fællesskab. Da OpenResty er bygget på NGINX, har det en bonus - det er NGINX-fællesskabetDet er meget stort, og en rimelig del af de spørgsmål, du måtte have i starten, er allerede løst af NGINX-samfundet.

    Lua-udviklereI går talte jeg med nogle fyre, der deltog i HighLoad++ træningsdagen, og jeg hørte, at kun Tarantool er skrevet i Lua. Det er ikke sandt, der er meget, der er skrevet i Lua. Eksempler: OpenResty, XMPP-serveren Prosody, spilmotoren Love2D, Lua bruges i Warcraft og andre steder. Der er mange Lua-udviklere, de har et stort og lydhøre fællesskab. Alle mine spørgsmål om Lua blev besvaret inden for få timer. Når man skriver til mailinglisten, er der bogstaveligt talt en masse svar inden for få minutter, der forklarer hvad og hvordan, og hvad der er hvad. Det er virkelig fantastisk. Desværre er ikke alle steder så venlige og imødekommende.
    Der er GitHub for OpenResty, hvor man kan oprette en issue, hvis noget er gået galt. Der er en mailingliste på Google Groups, hvor man kan diskutere generelle spørgsmål, og der er en mailingliste på kinesisk - måske kan du ikke engelsk, men har nogle færdigheder i kinesisk.

Resumé

  • Jeg håber, jeg har formidlet, at OpenResty er et meget praktisk framework, der er skabt til web.
  • Det har en lav indgangsbarriere, da koden ligner det, vi skriver; sproget er ret enkelt og minimalistisk.
  • Det tilbyder asynkron I/O uden callbacks, vi vil ikke få det rod, som vi nogle gange kan skrive i NodeJS.
  • Det har let deploy, da vi kun har brug for NGINX med det relevante modul og vores kode, så virker det hele med det samme.
  • Et stort og lydhør fællesskab.

Jeg fortalte ikke i detaljer, hvordan routing bliver lavet; det ville blive en meget lang fortælling.

Tak for din opmærksomhed!

Afspil video

Vladimir Protasov - OpenResty: gør NGINX til en fuldgyldig applikationsserver

Kilde: habr.com
Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster