OpenResty: van NGINX een volwaardige applicatieserver maken

OpenResty: van NGINX een volwaardige applicatieserver makenWe publiceren het transcript van het rapport van de conferentie opnieuw HighLoad ++ 2016, dat vorig jaar op 7 en 8 november in Skolkovo bij Moskou werd gehouden. Vladimir Protasov vertelt hoe de NGINX-functionaliteit kan worden uitgebreid met OpenResty en Lua.

Hallo allemaal, mijn naam is Vladimir Protasov, ik werk voor Parallels. Ik zal je wat over mezelf vertellen. Ik besteed driekwart van mijn leven aan het schrijven van code. Ik werd programmeur in hart en nieren in letterlijke zin: ik zie soms code in mijn dromen. Een kwart van het leven bestaat uit industriële ontwikkeling, het schrijven van code die rechtstreeks in productie gaat. Code die sommigen van jullie gebruiken maar niet kennen.

Om te laten weten hoe erg het was. Toen ik een beetje junior was, kwam ik binnen en ze gaven me deze twee terabyte databases. Het is nu hier voor iedereen highload. Ik ging naar conferenties en vroeg: “Jongens, vertel me, hebben jullie big data, is alles cool? Hoeveel bases heb je daar? Ze antwoordden me: "We hebben 100 gigabyte!" Ik zei: "Cool, 100 gigabyte!" En ik dacht bij mezelf hoe ik de pokerface netjes kon redden. Je denkt, ja, die jongens zijn cool, en dan kom je terug en sleutel je aan deze databases van meerdere terabytes. En dit is junior zijn. Kun je je voorstellen wat een hit het is?

Ik ken meer dan 20 programmeertalen. Dit is wat ik tijdens mijn werk moest uitzoeken. Ze geven je code in Erlang, in C, in C++, in Lua, in Python, in Ruby, in iets anders, en je moet het allemaal knippen. Over het algemeen moest ik. Het was niet mogelijk om het exacte aantal te berekenen, maar ergens rond de 20 was het aantal verloren.

Aangezien iedereen hier weet wat Parallels is en wat we doen, zal ik het niet hebben over hoe cool we zijn en wat we doen. Ik zal u alleen vertellen dat we 13 kantoren over de hele wereld hebben, meer dan 300 werknemers, ontwikkeling in Moskou, Tallinn en Malta. Als u wilt, kunt u naar Malta verhuizen als het in de winter koud is en u uw rug moet opwarmen.

Concreet schrijft onze afdeling in Python 2. We zijn in zaken en we hebben geen tijd om modieuze technologieën te introduceren, dus lijden we. We hebben Django, omdat het alles heeft, en we hebben het teveel genomen en weggegooid. Ook MySQL, Redis en NGINX. We hebben ook veel andere leuke dingen. We hebben MongoDB, we hebben konijnen die rondrennen, we hebben gewoon niets - maar het is niet van mij, en ik doe het niet.

OpenResty

Ik vertelde over mezelf. Laten we eens kijken waar ik het vandaag over ga hebben:

  • Wat is OpenResty en waarmee wordt het gegeten?
  • Waarom het wiel opnieuw uitvinden als we Python, NodeJS, PHP, Go en andere coole dingen hebben waar iedereen blij mee is?
  • En een paar praktijkvoorbeelden. Ik heb het rapport flink moeten inkorten, want ik kreeg het voor 3,5 uur, dus er zullen weinig voorbeelden zijn.

OpenResty is NGINX. Dankzij hem hebben we een volwaardige webserver, die goed geschreven is, hij werkt snel. Ik denk dat de meesten van ons NGINX gebruiken bij de productie. Jullie weten allemaal dat hij snel en cool is. Ze hebben er coole synchrone I / O in gemaakt, dus we hoeven niets te fietsen op dezelfde manier als gevent werd gefietst in Python. Gevent is cool, cool, maar als je C-code schrijft en er gaat iets mis met gevent, word je gek als je het debugt. Ik had ervaring: het kostte twee hele dagen om erachter te komen wat daar misging. Als iemand een paar weken eerder niet had gegraven, het probleem had gevonden, het op internet had geschreven en Google het niet had gevonden, dan waren we helemaal gek geworden.

NGINX doet al caching en statische content. U hoeft zich geen zorgen te maken over hoe u het op een menselijke manier moet doen, zodat u niet ergens langzamer gaat lopen, zodat u ergens descriptoren kwijtraakt. Nginx is erg handig om te implementeren, u hoeft niet na te denken over wat u moet nemen - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx is geïnstalleerd, gegeven aan de beheerders, ze weten hoe ze ermee moeten werken. Nginx handelt verzoeken op een gestructureerde manier af. Ik zal hier later over praten. Kortom, hij heeft een fase waarin hij het verzoek net heeft geaccepteerd, wanneer hij het heeft verwerkt en wanneer hij de inhoud aan de gebruiker heeft gegeven.

Nginx is cool, maar er is één probleem: het is niet flexibel genoeg, zelfs niet met al die coole functies die de jongens in de configuratie hebben gestopt, ondanks het feit dat het kan worden aangepast. Deze kracht is niet genoeg. Daarom hebben de jongens van Taobao er eens, ik denk zo'n acht jaar geleden, Lua ingebouwd. Wat geeft hij?

  • maat. Het is klein. LuaJIT geeft ongeveer 100-200 kilobytes aan geheugenoverhead en minimale prestatieoverhead.
  • snelheid. De LuaJIT-interpreter ligt in veel situaties dicht bij C, in sommige situaties verliest hij van Java, in andere haalt hij hem in. Een tijdlang werd het beschouwd als state-of-the-art, de coolste JIT-compiler. Nu zijn er coolere, maar die zijn erg zwaar, bijvoorbeeld dezelfde V8. Sommige JS-tolken en Java HotSpot zijn op sommige punten sneller, maar verliezen op sommige punten nog steeds.
  • Makkelijk te leren. Als je bijvoorbeeld een Perl-codebase hebt en je bent geen Booking, zul je geen Perl-programmeurs vinden. Omdat ze er niet zijn, zijn ze allemaal weggehaald en het is lang en moeilijk om ze te leren. Als je programmeurs voor iets anders wilt, moeten ze misschien ook worden omgeschoold of gevonden. In het geval van Lua is alles eenvoudig. Lua kan door elke junior in drie dagen worden geleerd. Het kostte me ongeveer twee uur om erachter te komen. Twee uur later was ik al code aan het schrijven in productie. Ongeveer een week later ging hij rechtstreeks naar de productie en vertrok.

Als resultaat ziet het er zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

Er is hier veel. OpenResty heeft een aantal modules samengesteld, zowel luash als motoren. En je hebt alles klaar - ingezet en werkend.

Примеры

Genoeg van de teksten, laten we verder gaan met de code. Hier is een beetje Hello World:

OpenResty: van NGINX een volwaardige applicatieserver maken

Wat is daar? dit is de locatie van de motor. We maken ons geen zorgen, we schrijven onze eigen routing niet, we nemen geen kant-en-klare route - we hebben het al in NGINX, we leven goed en lui.

content_by_lua_block is een blok dat zegt dat we inhoud aanbieden met behulp van een Lua-script. We nemen een engine-variabele remote_addr en schuif het erin string.format. Dit is hetzelfde als sprintf, alleen in Lua, alleen correct. En die geven we aan de klant.

Als resultaat ziet het er zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

Maar terug naar de echte wereld. In productie zet niemand Hello World in. Onze applicatie gaat meestal naar de database of ergens anders en wacht meestal op een reactie.

OpenResty: van NGINX een volwaardige applicatieserver maken

Gewoon zitten en wachten. Het is niet erg goed. Als er 100.000 gebruikers komen, is dat erg moeilijk voor ons. Laten we daarom een ​​eenvoudige toepassing als voorbeeld nemen. We gaan op zoek naar foto's, bijvoorbeeld katten. Alleen zullen we niet alleen zoeken, we zullen de trefwoorden uitbreiden en als de gebruiker zoekt naar "kittens", zullen we katten, pluisjes, enzovoort vinden. Eerst moeten we de verzoekgegevens op de backend krijgen. Het ziet er zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

Met twee regels kunt u GET-parameters ophalen, zonder complicaties. Vervolgens halen we deze informatie bijvoorbeeld uit een database met een tabel op trefwoord en extensie met behulp van een gewone SQL-query. Alles is eenvoudig. Het ziet er zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

Wij verbinden de bibliotheek resty.mysql, die we al in de kit hebben. We hoeven niets te installeren, alles is klaar. Specificeer hoe verbinding te maken en een SQL-query te maken:

OpenResty: van NGINX een volwaardige applicatieserver maken

Het is een beetje eng, maar het werkt. Hier is 10 de limiet. We halen 10 platen tevoorschijn, we zijn lui, we willen niet meer laten zien. In SQL was ik de limiet vergeten.

Vervolgens vinden we afbeeldingen voor alle zoekopdrachten. We verzamelen een aantal verzoeken en vullen een zogenaamde Lua-tabel in reqs, en doe ngx.location.capture_multi.

OpenResty: van NGINX een volwaardige applicatieserver maken

Al deze verzoeken gaan parallel en de antwoorden worden naar ons teruggestuurd. De looptijd is gelijk aan de reactietijd van de langzaamste. Als we allemaal terugschieten in 50 milliseconden, en we sturen honderd verzoeken, dan krijgen we binnen 50 milliseconden een reactie.

Omdat we lui zijn en geen HTTP-verwerking en caching willen schrijven, laten we NGINX alles voor ons doen. Zoals je zag, was er een verzoek om url/fetch, hier is hij:

OpenResty: van NGINX een volwaardige applicatieserver maken

Wij maken eenvoudig proxy_pass, specificeer waar te cachen, hoe het te doen, en alles werkt voor ons.

Maar dit is niet genoeg, we moeten de gegevens nog steeds aan de gebruiker geven. Het eenvoudigste idee is om alles eenvoudig in twee regels naar JSON te serialiseren. We geven Content-Type, we geven JSON.

Maar er is één moeilijkheid: de gebruiker wil JSON niet lezen. We moeten front-end developers aantrekken. Soms hebben we er in het begin geen zin in. Ja, en SEO-specialisten zullen zeggen dat als we naar foto's zoeken, het ze niet kan schelen. En als we ze wat inhoud geven, zullen ze zeggen dat onze zoekmachines niets indexeren.

Wat ermee te doen? Natuurlijk geven we de gebruiker HTML. Genereren met handgrepen is niet normaal, dus we willen sjablonen gebruiken. Hiervoor is er een bibliotheek lua-resty-template.

OpenResty: van NGINX een volwaardige applicatieserver maken

Je moet de drie gevreesde letters OPM gezien hebben. OpenResty wordt geleverd met een eigen pakketbeheerder, waarmee u een aantal verschillende modules kunt installeren, met name lua-resty-template. Het is een eenvoudige sjabloon-engine vergelijkbaar met Django-sjablonen. Daar kun je code schrijven en variabelen vervangen.

Als gevolg hiervan ziet alles er ongeveer zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

We hebben de gegevens genomen en de sjabloon opnieuw weergegeven in twee regels. De gebruiker is blij, heeft katten. Sinds we het verzoek hebben uitgebreid, heeft hij ook een pelsrob voor kittens gekregen. Je weet maar nooit, misschien was hij ernaar op zoek, maar kon hij zijn verzoek niet correct formuleren.

Alles is cool, maar we zijn in ontwikkeling en we willen het nog niet aan gebruikers laten zien. Laten we een autorisatie doen. Om dit te doen, laten we eens kijken hoe NGINX het verzoek afhandelt in termen van OpenResty:

  • Eerste fase - toegang, toen de gebruiker net kwam, en we keken naar hem op headers, op IP-adres, op andere gegevens. Je kunt het er meteen afhakken als we het niet lekker vinden. Dit kan worden gebruikt voor autorisatie, of als we veel verzoeken ontvangen, kunnen we ze in deze fase gemakkelijk afsnijden.
  • herschrijven. Sommige verzoekgegevens herschrijven.
  • content. We geven inhoud aan de gebruiker.
  • kopfilter. Wijzig de antwoordkoppen. Als we gebruikten proxy_pass, kunnen we sommige headers herschrijven voordat we deze aan de gebruiker geven.
  • lichaamsfilter. We kunnen het lichaam veranderen.
  • inloggen - loggen. Het is mogelijk om logs in elasticsearch te schrijven zonder een extra laag.

Onze autorisatie ziet er ongeveer zo uit:

OpenResty: van NGINX een volwaardige applicatieserver maken

We zullen het daaraan toevoegen location, die we eerder hebben beschreven, en plaats daar de volgende code:

OpenResty: van NGINX een volwaardige applicatieserver maken

We kijken of we een cookietoken hebben. Zo niet, dan gooien we op autorisatie. Gebruikers zijn sluw en raden misschien dat er een cookie-token moet worden ingesteld. Daarom zullen we het ook in Redis plaatsen:

OpenResty: van NGINX een volwaardige applicatieserver maken

De code voor het werken met Redis is heel eenvoudig en verschilt niet van andere talen. Tegelijkertijd blokkeert alle invoer / uitvoer, wat is er, wat is hier, niet. Als u synchrone code schrijft, werkt deze asynchroon. Zoals met gevent, alleen goed gedaan.

OpenResty: van NGINX een volwaardige applicatieserver maken

Laten we de autorisatie zelf doen:

OpenResty: van NGINX een volwaardige applicatieserver maken

We zeggen dat we de aanvraagtekst moeten lezen. We ontvangen POST-argumenten, controleer of de login en het wachtwoord correct zijn. Indien onjuist, dan gooien we op autorisatie. En als ze kloppen, schrijven we het token naar Redis:

OpenResty: van NGINX een volwaardige applicatieserver maken

Vergeet niet de cookie in te stellen, ook dit gebeurt in twee regels:

OpenResty: van NGINX een volwaardige applicatieserver maken

Het voorbeeld is eenvoudig, speculatief. Natuurlijk gaan we geen dienst maken die katten aan mensen laat zien. Maar wie kent ons. Dus laten we eens kijken wat er in productie kan worden gedaan.

  • Minimalistische achterkant. Soms moeten we nogal wat gegevens doorgeven aan de backend: ergens moeten we de datum vervangen, ergens moeten we een soort lijst weergeven, zeggen hoeveel gebruikers er nu op de site zijn, een teller opdraaien of statistieken. Iets zo kleins. Sommige minimale stukken kunnen heel gemakkelijk worden gemaakt. Dit zal snel, gemakkelijk en geweldig zijn.
  • Voorbewerking van gegevens. Soms willen we advertenties op onze pagina insluiten en accepteren we deze advertenties met API-verzoeken. Dat is hier heel gemakkelijk te doen. We laden onze backend niet, die is al hard aan het werk. U kunt hier ophalen en ophalen. We kunnen wat JS vormen of, integendeel, iets losmaken, voorbewerken voordat we het aan de gebruiker geven.
  • Gevel voor microservice. Dit is ook een heel goed geval, ik heb het geïmplementeerd. Daarvoor werkte ik voor Tenzor, een elektronisch rapportagebedrijf dat rapportage verzorgt voor ongeveer de helft van de rechtspersonen in het land. We hebben een service gemaakt, veel dingen worden daar gedaan met hetzelfde mechanisme: routering, autorisatie en meer.
    OpenResty kan worden gebruikt als de lijm voor uw microservices om één enkele toegang tot alles en één enkele interface te bieden. Omdat microservices zo kunnen worden geschreven dat je hier Node.js hebt, hier PHP, hier Python, hier iets met Erlang, begrijpen we dat we niet overal dezelfde code willen herschrijven. Daarom kan OpenResty in het front worden gestoken.

  • Statistieken en analyses. Meestal staat NGINX bij de ingang en gaan alle verzoeken er doorheen. Het is op deze plek dat het erg handig is om te verzamelen. Je kunt meteen iets uitrekenen en ergens naartoe gooien, bijvoorbeeld dezelfde Elasticsearch, Logstash, of gewoon naar het log schrijven en het dan ergens naartoe sturen.
  • Systemen voor meerdere gebruikers. Online games zijn bijvoorbeeld ook heel goed te doen. Alexander Gladysh zal je vandaag in Kaapstad vertellen hoe je snel een prototype kunt maken van een multiplayer-game met OpenResty.
  • Verzoekfiltering (WAF). Nu is het in de mode om allerlei soorten firewalls voor webapplicaties te maken, er zijn veel services die deze bieden. Met behulp van OpenResty kunt u voor uzelf een firewall voor webtoepassingen maken, die eenvoudig en gemakkelijk verzoeken filtert op basis van uw vereisten. Als je Python hebt, begrijp je dat PHP zeker niet in je zal worden geïnjecteerd, tenzij je het natuurlijk ergens vanaf de console spawnt. Je weet dat je MySQL en Python hebt. Waarschijnlijk kunnen ze hier proberen een soort directory-traversal uit te voeren en iets in de database te injecteren. Daarom kun je domme verzoeken snel en goedkoop vooraan uitfilteren.
  • Gemeenschap. Omdat OpenResty is gebaseerd op NGINX, heeft het een bonus - dit is NGINX-gemeenschap. Het is erg groot en veel van de vragen die je in eerste instantie zult hebben, zijn al beantwoord door de NGINX-gemeenschap.

    Lua-ontwikkelaars. Gisteren sprak ik met de jongens die naar de HighLoad++ trainingsdag kwamen en hoorden dat alleen Tarantool in Lua is geschreven. Dit is niet zo, veel dingen zijn in Lua geschreven. Voorbeelden: OpenResty, Prosody XMPP-server, Love2D-game-engine, Lua is geschreven in Warcraft en elders. Er zijn veel Lua-ontwikkelaars, ze hebben een grote en responsieve community. Al mijn Lua-vragen werden binnen een paar uur beantwoord. Als je naar de mailinglijst schrijft, zijn er letterlijk binnen een paar minuten al een heleboel antwoorden, ze beschrijven wat en hoe, wat is wat. Het is geweldig. Helaas is zo'n vriendelijke, oprechte gemeenschap niet overal.
    OpenResty heeft GitHub, waar je een probleem kunt openen als er iets kapot gaat. Er is een mailinglijst op Google Discussiegroepen waar je algemene zaken kunt bespreken, er is een mailinglijst in het Chinees - je weet maar nooit, misschien spreek je geen Engels, maar heb je kennis van het Chinees.

Resultaten van

  • Ik hoop dat ik heb kunnen overbrengen dat OpenResty een erg handig webframework is.
  • Het heeft een lage instapdrempel, aangezien de code vergelijkbaar is met wat we schrijven, de taal is vrij eenvoudig en minimalistisch.
  • Het biedt asynchrone I/O zonder callbacks, we zullen geen noedels hebben zoals we soms in NodeJS kunnen schrijven.
  • Het heeft een gemakkelijke implementatie, omdat we alleen NGINX nodig hebben met de juiste module en onze code, en alles werkt meteen.
  • Grote en responsieve gemeenschap.

Ik heb niet in detail verteld hoe routering in zijn werk gaat, het werd een heel lang verhaal.

Dank je wel!


Vladimir Protasov - OpenResty: van NGINX een volwaardige applicatieserver maken

Bron: www.habr.com

Voeg een reactie