OpenResty: trasformiamo NGINX in un server applicazioni completo

OpenResty: trasformiamo NGINX in un server applicazioni completoPubbliciamo di nuovo la trascrizione della relazione della conferenza HighLoad++ 2016, che si è tenuta a Skolkovo, nei sobborghi di Mosca, il 7-8 novembre dello scorso anno. Vladimir Protasov spiega come estendere le funzionalità di NGINX utilizzando OpenResty e Lua.

Ciao a tutti, sono Vladimir Protasov e lavoro in Parallels. Vi racconterò un po' di me. Ho trascorso tre quarti della mia vita scrivendo codice. Sono diventato un programmatore fino al midollo, nel senso letterale del termine: a volte sogno il codice. Un quarto della mia vita - sviluppo industriale, scrittura di codice che va direttamente in produzione. Il codice che alcuni di voi utilizzano senza rendersi conto.

Per farvi capire quanto fosse difficile. Quando ero un piccolo junior, arrivai e mi furono date queste enormi basi da due terabyte. Ora qui tutti sono highload. Andavo alle conferenze e chiedevo: «Ragazzi, raccontatemi, avete big data, tutto fantastico? Quante basi avete?». Mi rispondevano: «Abbiamo 100 gigabyte!» Io dicevo: «Fantastico, 100 gigabyte!» E pensavo come mantenere un po’ di poker face. Pensavi che sì, ragazzi, sono bravi, poi torni indietro e ti trovi a combattere con queste basi multi-terabyte. E questo - essendo un junior. Vi rendete conto di che colpo?

Conosco più di 20 linguaggi di programmazione. È ciò di cui ho dovuto occuparmi nel corso del lavoro. Ti danno codice in Erlang, C, C++, Lua, Python, Ruby, e altro, e devi fare tutto tu. Alla fine ci ho dovuto fare i conti. Non sono riuscito a contare esattamente il numero, ma ho perso il conto a circa 20.

Dato che tutti i presenti sanno cosa sia Parallels e cosa facciamo, non parlerò di quanto siamo bravi e cosa facciamo. Dirò solo che abbiamo 13 uffici in tutto il mondo, più di 300 dipendenti, sviluppo a Mosca, Tallin e Malta. Se volete, potete trasferirvi a Malta, se d'inverno fa freddo e volete scaldarvi.

Il nostro dipartimento specifico scrive in Python 2. Ci occupiamo di affari e non abbiamo tempo per implementare tecnologie alla moda, quindi soffriamo. Abbiamo Django, perché ha tutto, mentre abbiamo scartato ciò che era superfluo. Utilizziamo anche MySQL, Redis e NGINX. Abbiamo inoltre molte altre cose interessanti. Abbiamo MongoDB, abbiamo conigli che corrono, abbiamo di tutto - ma non è roba mia e non mi occupo di questo.

OpenResty

Ho parlato di me. Adesso vediamo di cosa parlerò oggi:

  • Cos'è OpenResty e come si usa?
  • Perché inventare un altro ciclismo, quando abbiamo Python, NodeJS, PHP, Go e altre fantastiche tecnologie di cui tutti sono contenti?
  • E un po' di esempi dalla vita reale. Ho dovuto ridurre drasticamente la presentazione, perché mi risultava di 3,5 ore, quindi ci saranno pochi esempi.

OpenResty è NGINX. Grazie a lui abbiamo un server web completo, ben scritto e veloce. Penso che la maggior parte di noi utilizzi NGINX in produzione. Tutti sapete che è veloce e fantastico. Ha un'eccellente gestione dell'input/output sincrono, quindi non dobbiamo reinventare la ruota come è successo con gevent in Python. Gevent è fantastico, ma se scrivete del codice in C e qualcosa va storto, con gevent vi sarete completamente impazziti a fare debug. Ho avuto un'esperienza del genere: ci sono voluti ben due giorni per capire cosa fosse andato storto. Se qualcuno non avesse scavato per settimane prima, non avesse trovato il problema, non avesse scritto su Internet e Google non lo avesse trovato, saremmo impazziti.

In NGINX ci sono già caching e contenuti statici. Non dovete affannarvi per capire come farlo bene, per non avere rallentamenti o per non perdere descrittori. Nginx è molto facile da implementare, non dovete preoccuparvi di cosa usare: WSGI, PHP-FPM, Gunicorn, Unicorn. Si installa Nginx, lo si passa agli amministratori e sanno come gestirlo. Nginx elabora le richieste in modo strutturato. Ne parlerò un po' più avanti. Brevemente, ha una fase in cui riceve la richiesta, una in cui la elabora e una in cui restituisce il contenuto all'utente.

Nginx è fantastico, ma c'è un problema: non è abbastanza flessibile, nonostante tutte quelle fantastiche funzionalità che gli sviluppatori hanno inserito nella configurazione, pur potendo essere personalizzato. Questa potenza non basta. Così, il team di Taobao, circa otto anni fa, ha integrato Lua. Cosa offre?

  • Dimensione. È leggero. LuaJIT ha un overhead di circa 100-200 kilobyte di memoria e un overhead minimo in termini di prestazioni.
  • Velocità. L'interprete LuaJIT in molte situazioni è vicino a C, in alcune situazioni perde contro Java, in altre la supera. Per un certo periodo è stato considerato il miglior JIT compiler. Ora ci sono compilatori migliori, ma molto più pesanti, come V8. Alcuni interpreti JS e il HotSpot di Java sono più veloci in certi punti, ma in alcune situazioni continuano a perdere.
  • Semplicità nell'apprendimento. Se, ad esempio, hai una base di codice in Perl e non sei Booking, non troverai programmatori Perl. Perché non ci sono, sono stati tutti presi, e insegnarli è lungo e difficile. Se hai bisogno di programmatori in qualcosa d'altro, probabilmente dovrai anche riqualificarli o trovarli. Nel caso di Lua, è tutto semplice. Lua può essere appreso da qualsiasi junior in tre giorni. Ho impiegato circa due ore per capire. Dopo due ore stavo già scrivendo codice in produzione. Dopo circa una settimana il codice era già in produzione.

Il risultato appare così:

OpenResty: trasformiamo NGINX in un server applicazioni completo

C'è molto qui. In OpenResty hanno messo insieme un sacco di moduli, sia Lua che di NGINX. E hai tutto pronto - hai deployato e funziona.

Esempi

Basta con la lirica, passiamo al codice. Ecco un semplice Hello World:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Cosa c'è qui? Questo è un location di NGINX. Non ci preoccupiamo, non scriviamo il nostro routing, non prendiamo qualcosa di pronto - abbiamo già tutto in NGINX, viviamo bene e comodamente.

content_by_lua_block è un blocco che indica che restituiamo contenuti tramite uno script Lua. Prendiamo la variabile di NGINX remote_addr e la passiamo a string.format. È esattamente la stessa cosa, solo in Lua, solo che corretta. E restituiamo al cliente. sprintfIl risultato apparirà così:

Ma torniamo nel mondo reale. In produzione nessuno deploya Hello World. Le nostre applicazioni di solito si connettono a un database o altrove e passano la maggior parte del tempo ad aspettare una risposta.

OpenResty: trasformiamo NGINX in un server applicazioni completo

Semplicemente siedono e aspettano. Questo non è molto buono. Quando arrivano 100.000 utenti, diventa molto difficile. Quindi, per esempio, costruiamo una semplice applicazione. Cercheremo immagini, ad esempio, di gatti. Non ci limiteremo a cercare, espanderemo le parole chiave e, se l'utente cerca 'gattini', gli troveremo gatti, pelosi e altro ancora. Prima di tutto, dobbiamo ottenere i dati della richiesta nel backend. Ecco come appare:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Due righe ti permettono di recuperare i parametri GET, nessuna complessità. Dopodiché, ad esempio, possiamo recuperare queste informazioni da un database con una tabella per parola chiave ed estensione tramite una normale query SQL. È tutto semplice. Ecco come appare:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Connettiamo la libreria

OpenResty: trasformiamo NGINX in un server applicazioni completo

resty.mysql , che abbiamo già nel pacchetto. Non dobbiamo installare nulla, è tutto pronto. Indichiamo come connetterci e facciamo la query SQL:, che abbiamo già in dotazione. Non dobbiamo installare nulla, è tutto pronto. Indichiamo come collegarci e facciamo la query SQL:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Qui è un po' spaventoso, ma tutto funziona. Qui 10 - è il limite. Ricaviamo 10 registrazioni, siamo pigri e non vogliamo mostrare di più. Ho dimenticato del limite in SQL.

Successivamente, troviamo le immagini per tutte le richieste. Raccogliamo un pacchetto di richieste e riempiamo una tabella Lua chiamata reqs, e facciamo ngx.location.capture_multi.

OpenResty: trasformiamo NGINX in un server applicazioni completo

Tutte queste richieste vanno in parallelo e riceviamo le risposte. Il tempo di esecuzione è pari al tempo di risposta di quella più lenta. Se tutte le nostre risposte sono in 50 millisecondi e abbiamo inviato cento richieste, la risposta arriverà in 50 millisecondi.

Poiché siamo pigri e non vogliamo scrivere la gestione HTTP e la memorizzazione nella cache, costringeremo NGINX a fare tutto per noi. Come hai visto, c'era una richiesta a url/fetch, ecco qui:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Facciamo una semplice proxy_pass, indichiamo dove memorizzare nella cache, come farlo, e tutto funziona.

Ma non basta, dobbiamo anche restituire i dati all'utente. L'idea più semplice è serializzare tutto in JSON, facile, in due righe. Restituiamo il Content-Type, restituiamo JSON.

Ma c'è una difficoltà: l'utente non vuole leggere JSON. Dobbiamo coinvolgere i frontendisti. A volte, inizialmente non ci va di farlo. E anche i SEO diranno che se stiamo cercando immagini, a loro non importa. Ma se forniamo qualche contenuto, diranno che i motori di ricerca non indicizzano nulla.

Cosa fare a riguardo? Naturalmente, restituiremo all'utente HTML. Generarlo a mano non è comodo, quindi vogliamo usare dei template. Per questo esiste la libreria lua-resty-template.

OpenResty: trasformiamo NGINX in un server applicazioni completo

Probabilmente hai visto tre lettere spaventose OPM. OpenResty viene con il suo gestore di pacchetti, attraverso il quale è possibile installare un sacco di moduli diversi, in particolare, lua-resty-template. È un motore di template semplice, simile ai template di Django. Puoi scrivere codice e fare sostituzioni di variabili.

Di conseguenza, tutto apparirà più o meno così:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Abbiamo preso i dati e abbiamo reso il template, di nuovo in due righe. L'utente è felice, ha ricevuto dei gattini. Poiché abbiamo ampliato la richiesta, ha ricevuto anche un foca. Chi lo sa, forse stava cercando proprio quello, ma non riusciva a formulare correttamente la sua richiesta.

Tutto è fantastico, ma siamo in fase di sviluppo e non vogliamo ancora mostrarlo agli utenti. Facciamo l'autenticazione. Per farlo, vediamo come NGINX gestisce le richieste in termini di OpenResty:

  • La prima fase - access, quando l'utente è appena arrivato, e lo abbiamo guardato in base ai titoli, all'indirizzo IP e ad altri dati. Possiamo subito disconnetterlo se non ci piace. Questo può essere utilizzato per l'autenticazione, oppure, se riceviamo molte richieste, possiamo facilmente interromperle in questa fase.
  • riscrivere. Riscriviamo alcuni dati della richiesta.
  • content. Forniamo il contenuto all'utente.
  • filtro intestazioni. Modifichiamo le intestazioni della risposta. Se abbiamo utilizzato proxy_pass, possiamo riscrivere alcune intestazioni prima di fornire il contenuto all'utente.
  • filtro corpo. Possiamo modificare il corpo.
  • registro — registrazione. Possiamo scrivere log in elasticsearch senza un ulteriore strato.

La nostra autenticazione apparirà più o meno così:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Aggiungeremo questo a quel location, che abbiamo descritto in precedenza, e inseriremo un codice del genere:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Controlliamo se abbiamo un token cookie. Se non ce l'abbiamo, rimandiamo all'autenticazione. Gli utenti sono astuti e possono indovinare che devono impostare un token cookie. Pertanto, lo salveremo anche in Redis:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Il codice per lavorare con Redis è molto semplice e non differisce da altri linguaggi. Inoltre, tutto l'input/output, sia lì che qui, è non bloccante. Se scrivi codice sincrono, funziona in modo asincrono. Circa come con gevent, solo fatto bene.

OpenResty: trasformiamo NGINX in un server applicazioni completo

Facciamo l'autenticazione stessa:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Diciamo che dobbiamo leggere il corpo della richiesta. Otteniamo gli argomenti POST, controlliamo che login e password siano corretti. Se non lo sono, rimandiamo all'autenticazione. Ma se sono corretti, salveremo il token in Redis:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Non dimentichiamo di impostare il cookie, questo si fa anche in due righe:

OpenResty: trasformiamo NGINX in un server applicazioni completo

Un esempio semplice, ipotetico. Certamente non faremo un servizio che mostra gattini alle persone. Anche se chi lo sa. Quindi esaminiamo ciò che è possibile fare in produzione.

  • Backend minimalista. A volte abbiamo bisogno di fornire al backend solo pochi dati: a volte dobbiamo inserire una data, a volte visualizzare una lista, dire quanti utenti ci sono attualmente sul sito, aggiungere un contatore o statistiche. Qualcosa di piccolo. Piccole sezioni minime possono essere fatte molto facilmente. Questo sarà veloce, facile e magnifico.
  • Preprocessing dei dati. A volte vogliamo integrare nella nostra pagina pubblicità, e prendiamo questa pubblicità tramite richieste API. È molto facile fare tutto ciò proprio qui. Non sovraccarichiamo il nostro backend, che già lavora duramente. Possiamo raccogliere tutto qui. Possiamo creare del codice JS o, al contrario, separarlo, preprocessarlo prima di consegnarlo all'utente.
  • Facciata per microservizi. Questo è anche un gran caso, l'ho realizzato. Prima lavoravo in un'azienda chiamata Tenzor, che si occupa di reportistica elettronica e garantisce la reportistica per circa la metà delle persone giuridiche nel paese. Abbiamo creato un servizio, molte cose come la routing, l'autenticazione e altro sono state realizzate usando lo stesso meccanismo.
    OpenResty può essere usato come collante per i tuoi microservizi, fornendo un accesso unificato a tutto e una singola interfaccia. Poiché i microservizi possono essere scritti in modo tale che qui hai Node.js, qui PHP, qui Python, qui c'è qualcosa su Erlang, comprendiamo che non vogliamo riscrivere lo stesso codice ovunque. Quindi, OpenResty può essere inserito nel frontend.
  • Statistiche e analisi. Di solito, NGINX si trova all'ingresso e tutte le richieste passano attraverso di esso. Proprio in questo punto è molto comodo raccogliere. Possiamo calcolare subito qualcosa e inviarlo da qualche parte, per esempio Elasticsearch, Logstash o semplicemente registrarlo nei log e poi inviarlo da qualche parte.
  • Sistemi multigiocatore. Ad esempio, è anche molto buono fare giochi online. Oggi a Cape Town, Alexander Gladys parlerà di come prototipare rapidamente un gioco multigiocatore utilizzando OpenResty.
  • Filtraggio delle richieste (WAF). Ora è di moda creare firewall per applicazioni web, ci sono molti servizi che li offrono. Con OpenResty puoi creare un firewall per applicazioni web che filtrerà facilmente le richieste secondo le tue esigenze. Se hai Python, capisci che PHP non sarà mai iniettato, a meno che tu non lo avvii da console da qualche parte. Sai che hai MySQL e Python. Probabilmente, possono tentare di fare qualche tipo di directory traversal e iniettare qualcosa nel database. Pertanto, è possibile filtrare rapidamente e a basso costo le richieste problematiche direttamente nel frontend.
  • Comunità. Poiché OpenResty è costruito su NGINX, ha un vantaggio: è la comunità NGINX. È molto grande e una buena parte delle domande che avrete inizialmente sono già state risolte dalla comunità NGINX.

    Sviluppatori Lua. Ieri ho parlato con alcuni ragazzi che sono venuti alla giornata di studio di HighLoad++ e ho sentito che solo Tarantool è scritto in Lua. Non è così, in Lua è stato scritto molto altro. Esempi: OpenResty, server XMPP Prosody, motore di gioco Love2D, Lua viene utilizzato in Warcraft e in altri luoghi. Ci sono molti sviluppatori Lua, hanno una comunità grande e reattiva. Tutte le mie domande su Lua sono state risolte in poche ore. Quando scrivi alla mailing list, dopo pochi minuti hai già un sacco di risposte che spiegano cosa e come, cosa significa. È fantastico. Purtroppo, non ovunque c'è una comunità così benevola.
    Per OpenResty c'è GitHub, dove si può aprire un'issue se qualcosa non funziona. C'è una mailing list su Google Groups dove si possono discutere questioni generali e una mailing list in cinese — magari non parlate inglese, ma conoscete il cinese.

Conclusioni

  • Spero di aver riuscito a far capire che OpenResty è un framework molto comodo, pensato per il web.
  • Ha una bassa barriera d'ingresso, poiché il codice è simile a quello su cui scriviamo, il linguaggio è piuttosto semplice e minimalista.
  • Fornisce I/O asincrono senza callback, non avremo spaghetti come a volte scriviamo in NodeJS.
  • Ha un facile deployment, poiché ci serve solo NGINX con il modulo necessario e il nostro codice, e tutto funziona immediatamente.
  • Una comunità grande e reattiva.

Non ho raccontato nei dettagli come funziona il routing, sarebbe diventato un racconto molto lungo.

Grazie per l'attenzione!

Guarda il video

Vladimir Protasov — OpenResty: trasformiamo NGINX in un server applicazioni completo

Fonte: habr.com
Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster