Pubblichiamo nuovamente la trascrizione del resoconto della conferenza 2016, che si è svolto a Skolkovo vicino a Mosca il 7 e 8 novembre dello scorso anno. spiega come estendere le funzionalità NGINX con OpenResty e Lua.
Ciao a tutti, mi chiamo Vladimir Protasov, lavoro presso Parallels. Ti parlerò un po' di me. Trascorro tre quarti della mia vita a scrivere codice. Sono diventato un programmatore nel vero senso della parola: a volte vedo il codice nei miei sogni. Un quarto della nostra vita è dedicato allo sviluppo industriale, alla scrittura di codici che vanno direttamente in produzione. Un codice che alcuni di voi usano ma non se ne rendono conto.
Quindi capisci quanto è stato brutto. Quando ero un ragazzino, sono arrivato e mi hanno dato questi database da due terabyte. È un carico pesante per tutti qui adesso. Sono andato alle conferenze e ho chiesto: “Ragazzi, ditemi, avete big data, va tutto bene? Quante basi hai lì? Mi hanno risposto: "Abbiamo 100 gigabyte!" Ho detto: "Fantastico, 100 gigabyte!" E stavo pensando tra me e me come mantenere con attenzione la mia faccia da poker. Pensi, sì, che i ragazzi siano fantastici, e poi torni indietro e armeggia con questi database da multi-terabyte. E questo è essere un junior. Riesci a immaginare che colpo sia questo?
Conosco più di 20 linguaggi di programmazione. Questo è qualcosa che dovevo capire mentre lavoravo. Ti danno il codice in Erlang, C, C++, Lua, Python, Ruby, qualcos'altro e devi tagliarlo tutto. In generale, dovevo farlo. Non è stato possibile calcolare il numero esatto, ma intorno al 20 il numero andò perduto.
Dato che tutti i presenti sanno cos'è Parallels e cosa facciamo, non parlerò di quanto siamo fantastici e di cosa facciamo. Ti dico solo che abbiamo 13 sedi nel mondo, più di 300 dipendenti, sviluppo a Mosca, Tallinn e Malta. Se lo desideri, puoi prenderlo e trasferirti a Malta se d’inverno fa freddo e hai bisogno di scaldarti la schiena.
Nello specifico, il nostro dipartimento scrive in Python 2. Siamo in affari e non abbiamo tempo per implementare tecnologie alla moda, quindi soffriamo. Usiamo Django perché ha tutto e abbiamo preso ciò che non era necessario e lo abbiamo buttato via. Anche MySQL, Redis e NGINX. Abbiamo anche molte altre cose interessanti. Abbiamo MongoDB, abbiamo conigli che corrono in giro, abbiamo tutto, ma non è mio e non lo faccio.
OpenResty
Ho raccontato di me. Scopriamo di cosa parlerò oggi:
- Cos'è OpenResty e con cosa si mangia?
- Perché reinventare un'altra ruota quando abbiamo Python, NodeJS, PHP, Go e altre cose interessanti di cui tutti sono contenti?
- E alcuni esempi dalla vita. Ho dovuto tagliare molto il report perché ci ho messo 3,5 ore, quindi ci saranno pochi esempi.
OpenResty è NGINX. Grazie a lui disponiamo di un server web completo, ben scritto e che funziona rapidamente. Penso che la maggior parte di noi utilizzi NGINX in produzione. Sapete tutti che è veloce e simpatico. Hanno creato un fantastico I/O sincrono, quindi non abbiamo bisogno di eseguire ciclicamente nulla, proprio come hanno fatto con Gevent in Python. Gevent è bello, fantastico, ma se scrivi codice C e qualcosa va storto, con Gevent diventerai matto nel debugging. Ho avuto l'esperienza: ci sono voluti due giorni interi per capire cosa è andato storto lì. Se qualcuno non avesse scavato per diverse settimane, non avesse trovato il problema, non avesse scritto su Internet e Google non lo avesse trovato, saremmo impazziti completamente.
NGINX ha già eseguito la memorizzazione nella cache e il contenuto statico. Non devi preoccuparti di come farlo umanamente, in modo da non rallentare da qualche parte, in modo da non perdere i descrittori da qualche parte. Nginx è molto comodo da implementare, non devi pensare a cosa prendere: WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx è stato installato, dato agli amministratori, sanno come lavorarci. Nginx elabora le richieste in modo strutturato. Ne parlerò un po' più tardi. In breve, ha una fase in cui ha appena accettato la richiesta, quando l'ha elaborata e quando ha servito il contenuto all'utente.
Nginx è interessante, ma c'è un problema: non è abbastanza flessibile, anche con tutte le funzionalità interessanti che i ragazzi hanno inserito nella configurazione, nonostante ciò che può essere configurato. Questo potere non è sufficiente. Ecco perché i ragazzi di Taobao, molto tempo fa, sembra otto anni fa, hanno inserito Lua nel progetto. Cosa dà?
- dimensione. È piccolo. LuaJIT fornisce circa 100-200 kilobyte di sovraccarico di memoria e un sovraccarico minimo di prestazioni.
- Velocità. L'interprete LuaJIT è vicino al C in molte situazioni, in alcune situazioni perde contro Java, in altre lo supera. Per qualche tempo è stato considerato lo stato dell'arte, il compilatore JIT più interessante. Ora ce ne sono di più freschi, ma sono molto pesanti, ad esempio lo stesso V8. Alcuni interpreti JS e Java HotSpot sono più veloci in alcuni punti, ma in altri continuano a perdere.
- Facile da imparare. Se hai, ad esempio, una base di codice Perl e non sei Booking, non troverai programmatori Perl. Poiché non esistono, sono stati tutti portati via, e insegnarli è lungo e difficile. Se desideri programmatori per qualcos'altro, potresti anche doverli riqualificare o trovarli. Nel caso di Lua, tutto è semplice. Qualsiasi junior può imparare Lua in tre giorni. Mi ci sono volute circa due ore per capirlo. Due ore dopo stavo già scrivendo il codice in produzione. Circa una settimana dopo andò direttamente alla produzione e se ne andò.
Di conseguenza, appare così:

C'è molto qui. OpenResty ha raccolto un sacco di moduli, sia luash che engine. E hai tutto pronto: distribuito e funzionante.
Примеры
Basta con i testi, passiamo al codice. Ecco un piccolo Ciao Mondo:

Cosa c'è qui? Questa è una posizione di Engins. Non ci preoccupiamo, non scriviamo il nostro routing, non ne prendiamo uno già pronto: lo abbiamo già in NGINX, viviamo una vita buona e pigra.
content_by_lua_block è un blocco che dice che stiamo offrendo contenuti utilizzando uno script Lua. Prendiamo la variabile Engins remote_addr e inserirlo string.format. Questo è lo stesso di sprintf, solo in Lua, solo corretto. E lo diamo al cliente.
Di conseguenza, sarà simile a questo:

Ma torniamo al mondo reale. Nessuno distribuisce Hello World in produzione. La nostra applicazione di solito va al database o da qualche altra parte e la maggior parte delle volte attende una risposta.

Si siede e aspetta. Non è molto buono. Quando arrivano 100.000 utenti, per noi è molto difficile. Usiamo quindi una semplice applicazione come esempio. Cercheremo immagini, ad esempio, di gatti. Ma non ci limiteremo a cercare, amplieremo le parole chiave e, se l’utente ha cercato “gattini”, troveremo gatti, gatti pelosi e così via. Innanzitutto, dobbiamo ottenere i dati della richiesta sul backend. Sembra questo:

Due righe ti consentono di raccogliere i parametri GET, senza complicazioni. Successivamente, diciamo, da un database con un segno per una parola chiave ed un'estensione, otteniamo queste informazioni utilizzando una normale query SQL. È semplice. Sembra questo:

Collegare la biblioteca resty.mysql, che abbiamo già nel kit. Non abbiamo bisogno di installare nulla, è tutto pronto. Indichiamo come connettersi ed effettuare una query SQL:

Fa un po' paura qui, ma funziona tutto. Qui 10 è il limite. Tiriamo fuori 10 voci, siamo pigri, non vogliamo mostrarne di più. Ho dimenticato il limite in SQL.
Successivamente troviamo le immagini per tutte le domande. Raccogliamo un sacco di richieste e compiliamo una tabella Lua chiamata reqs, e lo facciamo ngx.location.capture_multi.

Tutte queste richieste vengono inviate in parallelo e le risposte ci vengono restituite. Il tempo di funzionamento è pari al tempo di risposta di quello più lento. Se scattiamo tutti in 50 millisecondi e inviamo un centinaio di richieste, riceveremo una risposta in 50 millisecondi.
Dato che siamo pigri e non vogliamo scrivere HTTP e gestire la memorizzazione nella cache, faremo in modo che NGINX faccia tutto per noi. Come hai visto, c'era una richiesta per url/fetcheccolo qui:

Lo rendiamo semplice proxy_pass, indichiamo dove memorizzare nella cache, come farlo e tutto funziona per noi.
Ma questo non basta, bisogna comunque fornire i dati all’utente. L'idea più semplice è serializzare tutto in JSON, facilmente, su due righe. Diamo Content-Type, diamo JSON.
Ma c'è una difficoltà: l'utente non vuole leggere JSON. Dobbiamo attrarre sviluppatori front-end. A volte non vogliamo farlo all'inizio. E gli specialisti SEO diranno che se stiamo cercando immagini, a loro non importa. E se diamo loro dei contenuti, diranno che i nostri motori di ricerca non indicizzano nulla.
Cosa fare al riguardo? Naturalmente forniremo all'utente l'HTML. Generare a mano non è comme il faut, quindi vogliamo utilizzare i modelli. C'è una biblioteca per questo lua-resty-template.

Probabilmente hai visto le tre lettere spaventose OPM. OpenResty viene fornito con un proprio gestore di pacchetti, attraverso il quale è possibile installare una serie di moduli diversi, in particolare, lua-resty-template. Questo è un semplice motore di modelli, simile ai modelli Django. Lì puoi scrivere codice ed eseguire la sostituzione delle variabili.
Di conseguenza, tutto sarà simile a questo:

Abbiamo preso i dati e abbiamo renderizzato il modello, sempre su due righe. L'utente è felice, ha ricevuto i gatti. Dato che abbiamo ampliato la richiesta, ha ricevuto anche un sigillo di pelliccia per gattini. Non si sa mai, forse stava cercando proprio questo, ma non è riuscito a formulare correttamente la sua richiesta.
È tutto fantastico, ma siamo in fase di sviluppo e non vogliamo ancora mostrarlo agli utenti. Facciamo l'autorizzazione. Per fare ciò, diamo un'occhiata a come NGINX gestisce la richiesta in termini OpenResty:
- Prima fase - accesso, quando l'utente è appena arrivato e lo abbiamo esaminato in base alle intestazioni, all'indirizzo IP e ad altri dati. Possiamo interromperlo immediatamente se non ci piace. Questo può essere utilizzato per l'autorizzazione oppure, se riceviamo molte richieste, possiamo facilmente interromperle in questa fase.
- riscrivere. Riscriviamo alcuni dati della richiesta.
- contenuto. Forniamo il contenuto all'utente.
- filtro delle intestazioni. Sostituiamo le intestazioni di risposta. Se usassimo
proxy_pass, possiamo riscrivere alcune intestazioni prima di consegnarle all'utente. - filtro del corpo. Possiamo cambiare il corpo.
- ceppo - registrazione. Puoi scrivere log in elasticsearch senza un livello aggiuntivo.
La nostra autorizzazione sarà simile a questa:

Aggiungeremo questo a quello location, che abbiamo descritto prima, e abbiamo inserito il seguente codice:

Cerchiamo di vedere se abbiamo un cookie token. In caso contrario, chiediamo l'autorizzazione. Gli utenti sono furbi e riescono a indovinare che devono impostare un cookie token. Pertanto lo inseriremo anche in Redis:

Il codice per lavorare con Redis è molto semplice e non è diverso da altri linguaggi. Allo stesso tempo, tutti gli input/output, qua e là, non bloccano. Se scrivi codice sincrono, funziona in modo asincrono. Quasi come Gevent, ma fatto bene.

Facciamo l'autorizzazione stessa:

Diciamo che dobbiamo leggere il corpo della richiesta. Riceviamo argomenti POST e controlliamo che login e password siano corretti. Se non sono corretti, ti sfidiamo per l'autorizzazione. E se corretto, scrivi il token in Redis:

Non dimenticare di impostare il cookie, anche questo viene fatto su due righe:

L’esempio è semplice e speculativo. Naturalmente non realizzeremo un servizio che mostri i gatti alle persone. Ma chi ci conosce. Esaminiamo quindi cosa si può fare in produzione.
- Backend minimalista. A volte abbiamo bisogno di inviare solo pochi dati al backend: da qualche parte dobbiamo inserire una data, da qualche parte dobbiamo visualizzare un elenco, dire quanti utenti sono sul sito adesso, allegare un contatore o statistiche. Qualcosa di così piccolo. Alcuni pezzi minimi possono essere realizzati molto facilmente. Questo lo renderà veloce, facile e fantastico.
- Preelaborazione dei dati. A volte vogliamo incorporare pubblicità nella nostra pagina e riceviamo questa pubblicità utilizzando le richieste API. Questo è molto facile da fare qui. Non cariciamo il nostro backend, che è già seduto e lavora sodo. Puoi ritirarlo e ritirarlo qui. Possiamo mettere insieme un po' di JS o, al contrario, disaccoppiarlo e preelaborare qualcosa prima di fornirlo all'utente.
- Facciata per microservizi. Anche questo è un ottimo caso, l'ho implementato. Prima di allora, ho lavorato presso Tenzor, una società che si occupa di reporting elettronico e fornisce reporting a circa la metà delle persone giuridiche del Paese. Abbiamo creato un servizio, lì molte cose sono state fatte utilizzando lo stesso meccanismo: routing, autorizzazione e altro.
OpenResty può essere utilizzato come collante per i tuoi microservizi, fornendo un unico accesso a tutto e un'unica interfaccia. Poiché i microservizi possono essere scritti in modo tale da avere Node.js qui, PHP qui, Python qui, qualcosa di Erlang qui, comprendiamo che non vogliamo riscrivere lo stesso codice ovunque. Pertanto OpenResty può essere inserito nella parte anteriore. - Statistiche e analisi. Di solito NGINX è all’ingresso e tutte le richieste passano attraverso di esso. È in questo posto che è molto conveniente raccogliere. Puoi calcolare immediatamente qualcosa e caricarlo da qualche parte, ad esempio Elasticsearch, Logstash, o semplicemente scriverlo nel registro e quindi inviarlo da qualche parte.
- Sistemi multiutente. Ad esempio, anche i giochi online sono molto belli da realizzare. Oggi a Cape Town, Alexander Gladysh parlerà di come prototipare rapidamente un gioco multiplayer utilizzando OpenResty.
- Richiedi filtro (WAF). Al giorno d'oggi è di moda realizzare tutti i tipi di firewall per applicazioni web; ci sono molti servizi che li forniscono. Utilizzando OpenResty, puoi creare un firewall per applicazioni Web che filtrerà semplicemente e facilmente le richieste in base alle tue esigenze. Se hai Python, allora capisci che PHP non ti verrà sicuramente iniettato, a meno che, ovviamente, non lo generi ovunque dalla console. Sai di avere MySQL e Python. Probabilmente, potrebbero provare a fare una sorta di attraversamento delle directory e inserire qualcosa nel database. Pertanto, puoi filtrare le domande strane in modo rapido ed economico direttamente in primo piano.
- Comunità. Poiché OpenResty è basato su NGINX, ha un bonus: questo Comunità NGINX. È molto ampio e una buona parte delle domande che avrai all'inizio sono già state risolte dalla comunità NGINX.
Sviluppatori Lua. Ieri ho parlato con i ragazzi che sono venuti alla giornata di formazione HighLoad++ e ho sentito che solo Tarantool è scritto in Lua. Questo non è vero, molte cose sono scritte in Lua. Esempi: OpenResty, server Prosody XMPP, motore di gioco Love2D, Lua scritto in Warcraft e altrove. Ci sono molti sviluppatori Lua, hanno una comunità ampia e reattiva. Tutte le mie domande su Lua sono state risolte in poche ore. Quando scrivi alla mailing list, letteralmente nel giro di pochi minuti ci sono già un sacco di risposte, che descrivono cosa e come, cosa è cosa. È ottimo. Sfortunatamente, una comunità spirituale così gentile non è ovunque.
C'è GitHub per OpenResty, dove puoi aprire un problema se qualcosa non funziona. C'è una mailing list su Google Gruppi, dove puoi discutere di questioni generali, c'è una mailing list in cinese - non si sa mai, forse non parli inglese, ma conosci il cinese.
Risultati di
- Spero di essere riuscito a trasmettere che OpenResty è un framework molto conveniente su misura per il web.
- Ha una bassa barriera all'ingresso, poiché il codice è simile a quello in cui scriviamo, il linguaggio è abbastanza semplice e minimalista.
- Fornisce I/O asincrono senza callback, non avremo noodles come possiamo scrivere a volte in NodeJS.
- L'implementazione è semplice, poiché abbiamo bisogno solo di NGINX con il modulo necessario e il nostro codice, e tutto funziona immediatamente.
- Comunità ampia e reattiva.
Non ho raccontato in dettaglio come viene eseguito il routing, si è rivelata una storia molto lunga.
Grazie!

Fonte: habr.com
