Vi Äterpublicerar utskriften av rapporten frÄn konferensen 2016, som hölls i Skolkovo nÀra Moskva den 7-8 november förra Äret. berÀttar hur man utökar NGINX-funktionaliteten med OpenResty och Lua.
Hej alla, jag heter Vladimir Protasov, jag jobbar för Parallels. Jag ska berÀtta lite om mig sjÀlv. Jag Àgnar tre fjÀrdedelar av mitt liv Ät att skriva kod. Jag blev en programmerare till kÀrnan i bokstavlig mening: jag ser ibland kod i mina drömmar. En fjÀrdedel av livet Àr industriell utveckling, att skriva kod som gÄr direkt in i produktionen. Kod som nÄgra av er anvÀnder men inte kÀnner till det.
För att berĂ€tta hur illa det var. NĂ€r jag var liten kom jag in och de gav mig dessa tvĂ„ terabyte-databaser. Det Ă€r nu hĂ€r för alla highload. Jag gick pĂ„ konferenser och frĂ„gade: âGubbar, sĂ€g mig, har ni big data, Ă€r allt coolt? Hur mĂ„nga baser har du dĂ€r? De svarade mig: "Vi har 100 gigabyte!" Jag sa: "Cool, 100 gigabyte!" Och jag tĂ€nkte för mig sjĂ€lv hur man snyggt skulle kunna rĂ€dda pokeransiktet. Du tror, ââja, killarna Ă€r coola, och sedan kommer du tillbaka och pysslar med dessa multi-terabyte-databaser. Och det hĂ€r Ă€r att vara junior. Kan du förestĂ€lla dig vilken hit det Ă€r?
Jag kan mer Àn 20 programmeringssprÄk. Detta var vad jag var tvungen att ta reda pÄ under arbetets gÄng. De ger dig kod i Erlang, i C, i C++, i Lua, i Python, i Ruby, i nÄgot annat, och du mÄste klippa allt. I allmÀnhet var jag tvungen. Det var inte möjligt att berÀkna det exakta antalet, men nÄgonstans runt 20 gick siffran borta.
Eftersom alla hÀr vet vad Parallels Àr och vad vi gör kommer jag inte prata om hur coola vi Àr och vad vi gör. Jag ska bara berÀtta att vi har 13 kontor runt om i vÀrlden, mer Àn 300 anstÀllda, utveckling i Moskva, Tallinn och Malta. Om du vill kan du ta och flytta till Malta, om det Àr kallt pÄ vintern och du behöver vÀrma ryggen.
NĂ€rmare bestĂ€mt skriver vĂ„r avdelning i Python 2. Vi Ă€r i affĂ€rer och vi har inte tid att introducera fashionabla teknologier, sĂ„ vi lider. Vi har Django, för den har allt, och vi tog överskottet och slĂ€ngde det. Ăven MySQL, Redis och NGINX. Vi har ocksĂ„ en massa andra coola grejer. Vi har MongoDB, vi har kaniner som springer runt, vi har bara ingenting - men det Ă€r inte mitt, och jag gör det inte.
OpenResty
Jag berÀttade om mig sjÀlv. LÄt oss se vad jag ska prata om idag:
- Vad Àr OpenResty och vad Àts det med?
- Varför Äteruppfinna hjulet nÀr vi har Python, NodeJS, PHP, Go och andra coola grejer som alla Àr nöjda med?
- Och nÄgra verkliga exempel. Jag var tvungen att skÀra ner rapporten mycket, eftersom jag fick den i 3,5 timmar, sÄ det blir fÄ exempel.
OpenResty Àr NGINX. Tack vare honom har vi en fullfjÀdrad webbserver, som Àr vÀlskriven, den fungerar snabbt. Jag tror att de flesta av oss anvÀnder NGINX i produktionen. Ni vet alla att han Àr snabb och cool. De gjorde coola synkrona I/O i den, sÄ vi behöver inte cykla nÄgot pÄ samma sÀtt som gevent cyklades i Python. Gevent Àr coolt, coolt, men om du skriver C-kod och nÄgot gÄr fel med gevent kommer du att bli galen av att felsöka den. Jag hade erfarenhet: det tog tvÄ hela dagar att ta reda pÄ vad som gick fel dÀr. Om nÄgon inte hade grÀvt pÄ nÄgra veckor innan, hittat problemet, skrivit det pÄ internet och Google inte hittat det, dÄ hade vi blivit helt galna.
NGINX gör redan cachning och statiskt innehÄll. Du behöver inte oroa dig för hur du gör det mÀnskligt, sÄ att du inte saktar ner nÄgonstans, sÄ att du inte tappar deskriptorer nÄgonstans. Nginx Àr vÀldigt bekvÀmt att distribuera, du behöver inte tÀnka pÄ vad du ska ta - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx installerades, givet till administratörerna, de vet hur man arbetar med det. Nginx behandlar förfrÄgningar pÄ ett strukturerat sÀtt. Jag ska prata om detta lite senare. Kort sagt, han har en fas nÀr han precis accepterade förfrÄgan, nÀr han bearbetade och nÀr han gav innehÄllet till anvÀndaren.
Nginx Àr coolt, men det finns ett problem: det Àr inte tillrÀckligt flexibelt Àven med alla de dÀr coola funktionerna som killarna tryckte in i konfigurationen, trots att det gÄr att anpassa. Denna kraft rÀcker inte. DÀrför byggde killarna frÄn Taobao en gÄng, jag tror för ungefÀr Ätta Är sedan, in Lua i den. Vad ger han?
- Storlek. Den Àr liten. LuaJIT ger nÄgonstans runt 100-200 kilobyte minnesoverhead och minimal prestandaoverhead.
- ĐĄĐșĐŸŃĐŸŃŃŃ. LuaJIT-tolken Ă€r nĂ€ra C i mĂ„nga situationer, i vissa situationer förlorar den mot Java, i vissa kör den om den. Ett tag ansĂ„gs det vara toppmodernt, den coolaste JIT-kompilatorn. Nu finns det svalare, men de Ă€r vĂ€ldigt tunga, till exempel samma V8. Vissa JS-tolkar och Java HotSpot Ă€r snabbare pĂ„ vissa punkter, men förlorar fortfarande pĂ„ vissa punkter.
- LÀtt att lÀra. Om du har, sÀg, en Perl-kodbas och du inte bokar, kommer du inte att hitta Perl-programmerare. Eftersom de inte Àr dÀr togs de alla bort, och det Àr lÄngt och svÄrt att lÀra dem. Vill man ha programmerare till nÄgot annat kan de ocksÄ behöva omskolas eller hittas. NÀr det gÀller Lua Àr allt enkelt. Lua kan lÀras av alla juniorer pÄ tre dagar. Det tog mig ungefÀr tvÄ timmar att komma pÄ det. TvÄ timmar senare skrev jag redan kod i produktionen. UngefÀr en vecka senare gick han direkt till produktionen och gick.
Som ett resultat ser det ut sÄ hÀr:

Det finns mycket hÀr. OpenResty har satt ihop ett gÀng moduler, bÄde luash och motorer. Och du har allt klart - utplacerat och fungerar.
ĐŃĐžĐŒĐ”ŃŃ
Nog med sÄngtexterna, lÄt oss gÄ vidare till koden. HÀr Àr en liten Hello World:

Vad finns det? detta Àr motorns plats. Vi oroar oss inte, vi skriver inte vÄr egen routing, vi tar inte nÄgon fÀrdig - vi har den redan i NGINX, vi lever bra och lat.
content_by_lua_block Àr ett block som sÀger att vi serverar innehÄll med ett Lua-skript. Vi tar en motorvariabel remote_addr och skjut in den string.format. Detta Àr samma som sprintf, bara i Lua, bara korrekt. Och vi ger det till kunden.
Som ett resultat kommer det att se ut sÄ hÀr:

Men tillbaka till den verkliga vÀrlden. I produktionen anvÀnder ingen Hello World. VÄr applikation gÄr vanligtvis till databasen eller nÄgon annanstans och för det mesta vÀntar den pÄ svar.

Sitter bara och vÀntar. Det Àr inte sÀrskilt bra. NÀr 100.000 XNUMX anvÀndare kommer Àr det vÀldigt svÄrt för oss. LÄt oss dÀrför anvÀnda en enkel applikation som exempel. Vi kommer att leta efter bilder, till exempel katter. Bara vi kommer inte bara att söka, vi kommer att utöka nyckelorden och, om anvÀndaren sökte efter "kattungar", kommer vi att hitta katter, fluffies och sÄ vidare. Först mÄste vi fÄ förfrÄgningsdata pÄ backend. Det ser ut sÄ hÀr:

TvÄ rader lÄter dig plocka upp GET-parametrar, inga komplikationer. Sedan fÄr vi till exempel denna information frÄn en databas med en tabell per nyckelord och tillÀgg med hjÀlp av en vanlig SQL-frÄga. Allt Àr enkelt. Det ser ut sÄ hÀr:

Vi kopplar ihop biblioteket resty.mysql, som vi redan har i satsen. Vi behöver inte installera nÄgot, allt Àr klart. Ange hur du ansluter och gör en SQL-frÄga:

Det Àr lite lÀskigt, men det fungerar. HÀr Àr 10 grÀnsen. Vi drar ut 10 skivor, vi Àr lata, vi vill inte visa fler. I SQL glömde jag grÀnsen.
Sedan hittar vi bilder för alla frÄgor. Vi samlar ett gÀng förfrÄgningar och fyller i en Lua-tabell som heter reqs, och gör ngx.location.capture_multi.

Alla dessa förfrĂ„gningar gĂ„r parallellt, och svaren skickas tillbaka till oss. Körtiden Ă€r lika med svarstiden för den lĂ„ngsammaste. Om vi ââalla skjuter tillbaka pĂ„ 50 millisekunder, och vi skickade hundra förfrĂ„gningar, kommer vi att fĂ„ ett svar inom 50 millisekunder.
Eftersom vi Àr lata och inte vill skriva HTTP-hantering och cachelagring kommer vi att fÄ NGINX att göra allt Ät oss. Som ni sÄg fanns det en begÀran om url/fetch, hÀr Àr han:

Vi gör enkelt proxy_pass, ange var du ska cache, hur du gör det och allt fungerar för oss.
Men detta rÀcker inte, vi mÄste fortfarande ge data till anvÀndaren. Den enklaste idén Àr att serialisera allt till JSON, enkelt, i tvÄ rader. Vi ger Content-Type, vi ger JSON.
Men det finns en svÄrighet: anvÀndaren vill inte lÀsa JSON. Vi mÄste attrahera frontend-utvecklare. Ibland kÀnner vi inte för att göra det först. Ja, och SEO-specialister kommer att sÀga att om vi letar efter bilder, sÄ bryr de sig inte. Och om vi ger dem lite innehÄll kommer de att sÀga att vÄra sökmotorer inte indexerar nÄgonting.
Vad ska man göra med det? Naturligtvis kommer vi att ge anvÀndaren HTML. Att generera med handtag Àr inte comme il faut, sÄ vi vill anvÀnda mallar. Det finns ett bibliotek för detta lua-resty-template.

Du mÄste ha sett de tre fruktade bokstÀverna OPM. OpenResty kommer med sin egen pakethanterare, genom vilken du kan installera en massa olika moduler, i synnerhet, lua-resty-template. Det Àr en enkel mallmotor som liknar Django-mallar. DÀr kan du skriva kod och göra variabelsubstitution.
Som ett resultat kommer allt att se ut ungefÀr sÄ hÀr:

Vi tog data och renderade mallen igen pÄ tvÄ rader. AnvÀndaren Àr nöjd, fick katter. Eftersom vi utökade förfrÄgan fick han Àven en pÀlssÀl till kattungar. Man vet aldrig, han kanske letade efter det, men han kunde inte formulera sin begÀran korrekt.
Allt Àr coolt, men vi Àr under utveckling och vi vill inte visa anvÀndarna Ànnu. LÄt oss göra en auktorisation. För att göra detta, lÄt oss se hur NGINX hanterar begÀran nÀr det gÀller OpenResty:
- Första fasen - tillgÄng, nÀr anvÀndaren precis kom, och vi tittade pÄ honom efter rubriker, efter IP-adress, efter annan data. Du kan genast hugga av den om vi inte gillar den. Detta kan anvÀndas för auktorisering, eller om vi fÄr mÄnga förfrÄgningar kan vi enkelt hacka dem i denna fas.
- omskrivning. Skriver om en del förfrÄgningsdata.
- innehÄll. Vi ger innehÄll till anvÀndaren.
- rubrikfilter. Ăndra svarsrubriker. Om vi ââanvĂ€nde
proxy_pass, kan vi skriva om nÄgra rubriker innan vi ger det till anvÀndaren. - kroppsfilter. Vi kan förÀndra kroppen.
- log - loggning. Det Àr möjligt att skriva loggar i elasticsearch utan extra lager.
VÄr auktorisation kommer att se ut ungefÀr sÄ hÀr:

Vi lÀgger till det location, som vi beskrev tidigare, och satte följande kod dÀr:

Vi tittar för att se om vi har en cookie-token. Om inte, sÄ kastar vi pÄ auktorisation. AnvÀndare Àr listiga och kan gissa att en cookie-token mÄste stÀllas in. DÀrför kommer vi ocksÄ att lÀgga det i Redis:

Koden för att arbeta med Redis Àr vÀldigt enkel och skiljer sig inte frÄn andra sprÄk. Samtidigt, all input / output, vad som finns dÀr, vad som finns hÀr, det blockerar inte. Om du skriver synkron kod sÄ fungerar det asynkront. Som med gevent, bara gjort bra.

LÄt oss göra sjÀlva auktoriseringen:

Vi sÀger att vi mÄste lÀsa förfrÄgningsorganet. Vi fÄr POST-argument, kontrollera att inloggning och lösenord Àr korrekta. Om det Àr felaktigt, sÄ lÀgger vi pÄ auktorisation. Och om de Àr korrekta, sÄ skriver vi token till Redis:

Glöm inte att stÀlla in kakan, detta görs ocksÄ pÄ tvÄ rader:

Exemplet Àr enkelt, spekulativt. SjÀlvklart kommer vi inte att göra en tjÀnst som visar katter för mÀnniskor. Men vem kÀnner oss. SÄ lÄt oss gÄ igenom vad som kan göras i produktionen.
- Minimalistisk backend. Ibland behöver vi ge ut en hel del data till backend: nÄgonstans mÄste vi ersÀtta datumet, nÄgonstans mÄste vi visa nÄgon slags lista, sÀga hur mÄnga anvÀndare som Àr pÄ sajten nu, skruva pÄ en rÀknare eller statistik. NÄgot sÄ litet. Vissa minimala bitar kan göras mycket enkelt. Detta kommer att bli snabbt, enkelt och bra.
- Dataförbehandling. Ibland vill vi bÀdda in annonser pÄ vÄr sida, och vi tar dessa annonser med API-förfrÄgningar. Detta Àr vÀldigt enkelt att göra hÀr. Vi laddar inte vÄr backend, som redan jobbar hÄrt. Du kan hÀmta och hÀmta hÀr. Vi kan forma en del JS eller tvÀrtom lossa, förbehandla nÄgot innan vi ger det till anvÀndaren.
- Fasad för mikroservice. Detta Àr ocksÄ ett mycket bra fall, jag genomförde det. Innan dess arbetade jag för Tenzor, ett elektroniskt rapporteringsföretag som tillhandahÄller rapportering för ungefÀr hÀlften av de juridiska personerna i landet. Vi har skapat en tjÀnst, mÄnga saker görs dÀr med samma mekanism: routing, auktorisering och mer.
OpenResty kan anvÀndas som lim för dina mikrotjÀnster för att ge en enda Ätkomst till allt och ett enda grÀnssnitt. Eftersom mikrotjÀnster kan skrivas pÄ ett sÄdant sÀtt att du har Node.js hÀr, du har PHP hÀr, du har Python hÀr, det finns nÄgon Erlang-grej hÀr, vi förstÄr att vi inte vill skriva om samma kod överallt. DÀrför kan OpenResty kopplas in i fronten. - Statistik och analyser. Vanligtvis Àr NGINX vid ingÄngen, och alla förfrÄgningar gÄr igenom den. Det Àr pÄ denna plats som det Àr mycket bekvÀmt att samla. Du kan omedelbart berÀkna nÄgot och slÀnga det nÄgonstans, till exempel samma Elasticsearch, Logstash, eller bara skriva det till loggen och sedan skicka det nÄgonstans.
- FleranvÀndarsystem. Till exempel Àr onlinespel ocksÄ vÀldigt bra att göra. Idag i Kapstaden kommer Alexander Gladysh att berÀtta för dig hur du snabbt prototypar ett spel för flera spelare med OpenResty.
- BegÀr filtrering (WAF). Nu Àr det pÄ modet att göra alla typer av webbapplikationsbrandvÀggar, det finns mÄnga tjÀnster som tillhandahÄller dem. Med hjÀlp av OpenResty kan du göra dig sjÀlv en webbapplikationsbrandvÀgg, som enkelt och enkelt filtrerar förfrÄgningar efter dina krav. Om du har Python förstÄr du att PHP definitivt inte kommer att injiceras till dig, sÄvida du naturligtvis inte skapar det nÄgonstans frÄn konsolen. Du vet att du har MySQL och Python. Förmodligen kan de hÀr försöka göra nÄgon form av katalogtraversering och injicera nÄgot i databasen. DÀrför kan du filtrera bort dumma förfrÄgningar snabbt och billigt direkt lÀngst fram.
- Gemenskap. Eftersom OpenResty Ă€r baserat pĂ„ NGINX har det en bonus â det hĂ€r Ă€r NGINX community. Den Ă€r vĂ€ldigt stor och mĂ„nga av de frĂ„gor du kommer att ha till en början har redan besvarats av NGINX-communityt.
Lua utvecklare. IgÄr pratade jag med killarna som kom till HighLoad ++ trÀningsdagen och hörde att bara Tarantool Àr skrivet i Lua. Det Àr inte sÄ, mÄnga saker skrivs i Lua. Exempel: OpenResty, Prosody XMPP-server, Love2D-spelmotor, Lua Àr skriptad i Warcraft och pÄ andra stÀllen. Det finns mÄnga Lua-utvecklare, de har en stor och lyhörd community. Alla mina Lua-frÄgor besvarades inom nÄgra timmar. NÀr du skriver till e-postlistan finns det bokstavligen pÄ nÄgra minuter redan ett gÀng svar, de beskriver vad och hur, vad Àr vad. Det Àr toppen. TyvÀrr finns inte en sÄdan uppriktig gemenskap överallt.
OpenResty har GitHub, dÀr du kan öppna ett problem om nÄgot gÄr sönder. Det finns en e-postlista pÄ Google Groups dÀr du kan diskutera allmÀnna frÄgor, det finns en e-postlista pÄ kinesiska - du vet aldrig, du kanske inte pratar engelska, men du har kunskaper i kinesiska.
Resultat av
- Jag hoppas att jag kunde förmedla att OpenResty Àr ett mycket bekvÀmt webbramverk.
- Den har en lÄg tröskel för intrÀde, eftersom koden liknar det vi skriver, Àr sprÄket ganska enkelt och minimalistiskt.
- Det ger asynkron I/O utan callbacks, vi kommer inte ha nudlar som vi ibland kan skriva i NodeJS.
- Den har en enkel implementering, eftersom vi bara behöver NGINX med rÀtt modul och vÄr kod, och allt fungerar direkt.
- Stor och lyhörd gemenskap.
Jag berÀttade inte i detalj hur routing gÄr till, det visade sig vara en vÀldigt lÄng historia.
Tack för din uppmÀrksamhet!

KĂ€lla: will.com
