OpenResty: converte NGINX nun servidor de aplicacións completo

OpenResty: converte NGINX nun servidor de aplicacións completoVolvemos a publicar a transcrición do relatorio da xornada HighLoad++ 2016, que se celebrou en Skolkovo preto de Moscova os días 7 e 8 de novembro do ano pasado. Vladimir Protasov di como estender a funcionalidade de NGINX con OpenResty e Lua.

Ola a todos, chámome Vladimir Protasov, traballo para Parallels. Vouche falar un pouco de min. Levo tres cuartos da miña vida escribindo código. Convertínme nun programador ata o núcleo no sentido literal: ás veces vexo código nos meus soños. Unha cuarta parte da vida é desenvolvemento industrial, escribindo código que entra directamente á produción. Código que algúns de vós usades pero non o coñecedes.

Para que saibas o mal que foi. Cando era un pequeno, entrei e déronme estas bases de datos de dous terabytes. Agora está aquí para todos. Fun a conferencias e preguntei: “Chicos, dime, tes big data, está todo ben? Cantas bases tes alí? Contestáronme: "Temos 100 gigabytes!" Dixen: "Xenial, 100 gigabytes!" E pensei para min como salvar a cara do póker. Pensas que si, os mozos son xeniais, e despois volves e xogas con estas bases de datos de varios terabytes. E isto é ser junior. Imaxínate o éxito que é?

Coñezo máis de 20 linguaxes de programación. Isto é o que tiven que descubrir no curso do traballo. Danche código en Erlang, en C, en C++, en Lua, en Python, en Ruby, noutra cousa, e tes que cortalo todo. En xeral, tiven que facelo. Non foi posible calcular o número exacto, pero nalgún lugar arredor dos 20 perdeuse o número.

Xa que todos aquí saben o que é Parallels e o que facemos, non vou falar do xenial que somos e do que facemos. Só direi que temos 13 oficinas en todo o mundo, máis de 300 empregados, desenvolvemento en Moscova, Tallin e Malta. Se o desexa, pode levar e trasladarse a Malta, se fai frío no inverno e precisa quentar as costas.

En concreto, o noso departamento escribe en Python 2. Estamos na empresa e non temos tempo para introducir tecnoloxías de moda, polo que sufrimos. Temos a Django, porque ten de todo, e quitamos o exceso e tiramos. Tamén MySQL, Redis e NGINX. Tamén temos moitas outras cousas interesantes. Temos MongoDB, temos coellos correndo, simplemente non temos nada, pero non é meu e non o fago.

OpenResty

Falei de min. A ver de que vou falar hoxe:

  • Que é OpenResty e con que se come?
  • Por que reinventar a roda cando temos Python, NodeJS, PHP, Go e outras cousas interesantes coas que todos están contentos?
  • E algúns exemplos da vida real. Tiven que reducir moito o informe, porque o conseguín durante 3,5 horas, polo que haberá poucos exemplos.

OpenResty é NGINX. Grazas a el, temos un servidor web completo, que está ben escrito, funciona rápido. Creo que a maioría de nós usamos NGINX na produción. Todos sabedes que é rápido e xenial. Fixeron E/S síncronas xeniais nel, polo que non necesitamos ciclar nada do mesmo xeito que se ciclou gevent en Python. Gevent é xenial, xenial, pero se escribes código C e algo sae mal con gevent, volverás tolo depurándoo. Tiven experiencia: tardou dous días enteiros en descubrir o que estaba mal alí. Se alguén non tivese escavado durante unhas semanas antes, atopara o problema, o escribise en Internet e Google non o atopase, entón teriamos toleados por completo.

NGINX xa fai caché e contido estático. Non tes que preocuparte de como facelo humanamente, para non frear nalgún lugar, para non perder os descritores nalgún lugar. Nginx é moi cómodo de implementar, non necesitas pensar que tomar: WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx instalouse, entregouse aos administradores, saben como traballar con el. Nginx xestiona as solicitudes de forma estruturada. Disto falarei un pouco máis adiante. En definitiva, ten unha fase na que acaba de aceptar a solicitude, na que a tramita e na que lle cede o contido ao usuario.

Nginx é xenial, pero hai un problema: non é o suficientemente flexible mesmo con todas esas funcións interesantes que os mozos introduciron na configuración, a pesar de que se pode personalizar. Este poder non é suficiente. Polo tanto, os mozos de Taobao, creo que hai uns oito anos, construíron Lua. Que dá?

  • Tamaño. É pequeno. LuaJIT ofrece uns 100-200 kilobytes de sobrecarga de memoria e unha sobrecarga de rendemento mínima.
  • Acelerar. O intérprete LuaJIT está preto de C en moitas situacións, nalgunhas situacións pérdese ante Java, noutras o supera. Durante un tempo, considerouse o estado da arte, o compilador JIT máis xenial. Agora hai outros máis frescos, pero son moi pesados, por exemplo, o mesmo V8. Algúns intérpretes JS e Java HotSpot son máis rápidos nalgúns puntos, pero aínda perden nalgúns momentos.
  • Fácil de aprender. Se tes, por exemplo, unha base de código Perl e non estás reservando, non atoparás programadores de Perl. Como non están, quitáronlles todos, e é longo e difícil ensinalos. Se queres programadores para outra cousa, é posible que tamén teñan que ser adestrados ou atopados. No caso de Lua, todo é sinxelo. A lúa pode aprendera calquera xuvenil en tres días. Tardei unhas dúas horas en descubrilo. Dúas horas despois, xa estaba escribindo código en produción. Aproximadamente unha semana despois, pasou directamente á produción e marchou.

Como resultado, ten o seguinte aspecto:

OpenResty: converte NGINX nun servidor de aplicacións completo

Hai moito aquí. OpenResty montou unha morea de módulos, tanto luash como engins. E tes todo listo: despregado e funcionando.

Exemplos

Basta coa letra, pasemos ao código. Aquí tes un pequeno Ola mundo:

OpenResty: converte NGINX nun servidor de aplicacións completo

Que hai? esta é a localización do motor. Non nos preocupamos, non escribimos o noso propio enrutamento, non levamos algún preparado: xa o temos en NGINX, vivimos ben e con preguiza.

content_by_lua_block é un bloque que di que estamos a servir contido mediante un script Lua. Tomamos unha variable engins remote_addr e metelo dentro string.format. Este é o mesmo que sprintf, só en Lua, só correcto. E dámosllo ao cliente.

Como resultado, quedará así:

OpenResty: converte NGINX nun servidor de aplicacións completo

Pero de volta ao mundo real. Na produción, ninguén desprega Hello World. A nosa aplicación adoita ir á base de datos ou a outro lugar e a maioría das veces agarda unha resposta.

OpenResty: converte NGINX nun servidor de aplicacións completo

Só senta e espera. Non é moi bo. Cando chegan 100.000 usuarios, é moi difícil para nós. Polo tanto, usemos unha aplicación sinxela como exemplo. Buscaremos imaxes, por exemplo, gatos. Só que non só buscaremos, ampliaremos as palabras clave e, se o usuario buscou "gatiños", atoparemos gatos, peluches, etc. Primeiro necesitamos obter os datos da solicitude no backend. Parece así:

OpenResty: converte NGINX nun servidor de aplicacións completo

Dúas liñas permítenche recoller os parámetros GET, sen complicacións. Despois, por exemplo, obtemos esta información dunha base de datos cunha táboa por palabra clave e extensión mediante unha consulta SQL normal. Todo é sinxelo. Parece así:

OpenResty: converte NGINX nun servidor de aplicacións completo

Conectamos a biblioteca resty.mysql, que xa temos no kit. Non necesitamos instalar nada, xa está todo listo. Especifique como conectarse e facer unha consulta SQL:

OpenResty: converte NGINX nun servidor de aplicacións completo

Dá un pouco de medo, pero funciona. Aquí 10 é o límite. Sacamos 10 discos, somos preguiceiros, non queremos mostrar máis. En SQL, esquecín o límite.

Despois atopamos imaxes para todas as consultas. Recollemos unha morea de solicitudes e enchemos unha táboa Lua chamada reqs, e fai ngx.location.capture_multi.

OpenResty: converte NGINX nun servidor de aplicacións completo

Todas estas peticións van en paralelo, e as respostas son devoltos. O tempo de execución é igual ao tempo de resposta do máis lento. Se todos disparamos en 50 milisegundos e enviamos cen solicitudes, entón recibiremos unha resposta en 50 milisegundos.

Xa que somos preguiceiros e non queremos escribir o manexo HTTP e a caché, faremos que NGINX faga todo por nós. Como viches, houbo unha solicitude de url/fetch, aquí está:

OpenResty: converte NGINX nun servidor de aplicacións completo

Facemos sinxelo proxy_pass, especifica onde almacenar na caché, como facelo e todo funciona para nós.

Pero isto non é suficiente, aínda hai que darlle os datos ao usuario. A idea máis sinxela é serializar todo a JSON, facilmente, en dúas liñas. Damos Content-Type, damos JSON.

Pero hai unha dificultade: o usuario non quere ler JSON. Necesitamos atraer desenvolvedores front-end. Ás veces non temos ganas de facelo ao principio. Si, e os especialistas en SEO dirán que se buscamos imaxes, non lles importa. E se lles damos algún contido, dirán que os nosos buscadores non indexan nada.

Que facer con el? Por suposto, darémoslle HTML ao usuario. Xerar con identificadores non é comme il faut, polo que queremos usar modelos. Hai unha biblioteca para iso lua-resty-template.

OpenResty: converte NGINX nun servidor de aplicacións completo

Debes ter visto as tres temidas letras OPM. OpenResty inclúe o seu propio xestor de paquetes, a través do cal pode instalar unha morea de módulos diferentes, en particular, lua-resty-template. É un motor de modelos sinxelo semellante aos modelos de Django. Alí pode escribir código e facer substitución de variables.

Como resultado, todo terá un aspecto así:

OpenResty: converte NGINX nun servidor de aplicacións completo

Collemos os datos e representamos o modelo de novo en dúas liñas. O usuario está contento, ten gatos. Dado que ampliamos a solicitude, tamén recibiu unha foca para gatiños. Nunca se sabe, quizais o estaba a buscar, pero non puido formular correctamente a súa solicitude.

Todo está ben, pero estamos en desenvolvemento e aínda non queremos mostrar aos usuarios. Fagamos unha autorización. Para facelo, vexamos como NGINX xestiona a solicitude en termos de OpenResty:

  • primeira fase - acceso, cando o usuario acaba de chegar, e o miramos por cabeceiras, por enderezo IP, por outros datos. Podes cortalo inmediatamente se non nos gusta. Isto pódese utilizar para a autorización ou, se recibimos moitas solicitudes, podemos cortalas facilmente nesta fase.
  • reescribir. Reescribindo algúns datos da solicitude.
  • contido. Dámoslle contido ao usuario.
  • filtro de cabeceira. Cambia as cabeceiras das respostas. Se usamos proxy_pass, podemos reescribir algunhas cabeceiras antes de entregalas ao usuario.
  • filtro corporal. Podemos cambiar o corpo.
  • sesión - rexistro. É posible escribir rexistros en elasticsearch sen unha capa adicional.

A nosa autorización terá un aspecto así:

OpenResty: converte NGINX nun servidor de aplicacións completo

Engadirémolo a iso location, que describimos antes, e poñemos alí o seguinte código:

OpenResty: converte NGINX nun servidor de aplicacións completo

Miramos se temos un token de cookie. Se non, entón botamos a autorización. Os usuarios son astutos e poden adiviñar que hai que configurar un token de cookie. Polo tanto, tamén o poñeremos en Redis:

OpenResty: converte NGINX nun servidor de aplicacións completo

O código para traballar con Redis é moi sinxelo e non se diferencia doutros idiomas. Ao mesmo tempo, todas as entradas / saídas, o que hai, o que está aquí, non está bloqueando. Se escribe código sincrónico, entón funciona de forma asíncrona. Como con gevent, só feito ben.

OpenResty: converte NGINX nun servidor de aplicacións completo

Fagamos a propia autorización:

OpenResty: converte NGINX nun servidor de aplicacións completo

Dicimos que necesitamos ler o corpo da solicitude. Recibimos argumentos POST, comprobe que o inicio de sesión e o contrasinal son correctos. Se non é incorrecto, solicitamos a autorización. E se son correctas, escribimos o token a Redis:

OpenResty: converte NGINX nun servidor de aplicacións completo

Non esquezas configurar a galleta, isto tamén se fai en dúas liñas:

OpenResty: converte NGINX nun servidor de aplicacións completo

O exemplo é sinxelo, especulativo. Por suposto, non faremos un servizo que mostre gatos á xente. Pero quen nos coñece. Entón, imos repasar o que se pode facer na produción.

  • Backend minimalista. Ás veces temos que dar bastantes datos ao backend: nalgún lugar hai que substituír a data, nalgún lugar hai que mostrar algún tipo de lista, dicir cantos usuarios hai no sitio agora, facer un contador ou estatísticas. Algo tan pequeno. Algunhas pezas mínimas pódense facer moi facilmente. Isto será rápido, sinxelo e xenial.
  • Preprocesamento de datos. Ás veces queremos inserir anuncios na nosa páxina e tomamos estes anuncios con solicitudes de API. Isto é moi sinxelo de facer aquí. Non cargamos o noso backend, que xa está a traballar duro. Podes recoller e recoller aquí. Podemos moldear algún JS ou, pola contra, desenganchar, preprocesar algo antes de cederllo ao usuario.
  • Fachada para microservizo. Este tamén é un moi bo caso, implementei. Antes diso, traballei para Tenzor, unha empresa de informes electrónicos que ofrece informes para preto da metade das persoas xurídicas do país. Fixemos un servizo, alí fanse moitas cousas usando o mesmo mecanismo: enrutamento, autorización, etc.
    OpenResty pódese usar como pegamento para os teus microservizos para proporcionar un único acceso a todo e unha única interface. Dado que os microservizos poden escribirse de tal xeito que tes Node.js aquí, tes PHP aquí, tes Python aquí, hai algo de Erlang aquí, entendemos que non queremos reescribir o mesmo código en todas partes. Polo tanto, OpenResty pódese conectar na parte frontal.

  • Estatística e analítica. Normalmente NGINX está na entrada e todas as solicitudes pasan por ela. É neste lugar onde é moi cómodo recoller. Podes calcular algo inmediatamente e botalo nalgún lugar, por exemplo, o mesmo Elasticsearch, Logstash, ou simplemente escribilo no rexistro e envialo a algún lugar.
  • Sistemas multiusuario. Por exemplo, os xogos en liña tamén son moi bos para facer. Hoxe, en Cidade do Cabo, Alexander Gladysh dirá como crear un prototipo rápido dun xogo multixogador usando OpenResty.
  • Filtrado de solicitudes (WAF). Agora está de moda facer todo tipo de cortalumes de aplicacións web, son moitos os servizos que os proporcionan. Coa axuda de OpenResty, podes facerte un firewall de aplicacións web, que filtrará de xeito sinxelo e sinxelo as solicitudes segundo as túas necesidades. Se tes Python, entendes que PHP definitivamente non se che inxectará, a menos que, por suposto, o desexes en calquera lugar da consola. Sabes que tes MySQL e Python. Probablemente, aquí poden tentar facer algún tipo de percorrido do directorio e inxectar algo na base de datos. Polo tanto, pode filtrar as solicitudes tontas de forma rápida e barata desde a fronte.
  • Comunidade. Dado que OpenResty está baseado en NGINX, ten unha bonificación: isto é Comunidade NGINX. É moi grande, e moitas das preguntas que terás nun principio xa foron respondidas pola comunidade NGINX.

    Desenvolvedores Lua. Onte falei cos rapaces que viñeron á xornada de adestramento HighLoad ++ e escoitei que só Tarantool está escrito en Lua. Non é así, moitas cousas están escritas en Lua. Exemplos: OpenResty, servidor Prosody XMPP, motor de xogo Love2D, Lua está escrito en Warcraft e noutros lugares. Hai moitos desenvolvedores de Lua, teñen unha comunidade grande e sensible. Todas as miñas preguntas de Lua foron respondidas en poucas horas. Cando escribes á lista de correo, literalmente en poucos minutos xa hai unha morea de respostas, describen que e como, que é que. É xenial. Desafortunadamente, unha comunidade tan amable e sincera non está en todas partes.
    OpenResty ten GitHub, onde podes abrir un problema se algo se rompe. Hai unha lista de correo en Grupos de Google onde podes falar de cuestións xerais, hai unha lista de correo en chinés; nunca se sabe, quizais non fales inglés, pero tes coñecementos de chinés.

Resultados de

  • Espero poder transmitir que OpenResty é un marco moi cómodo adaptado para a web.
  • Ten un baixo limiar de entrada, xa que o código é semellante ao que escribimos, a linguaxe é bastante sinxela e minimalista.
  • Ofrece E/S asíncrona sen devolucións de chamada, non teremos fideos xa que ás veces podemos escribir en NodeJS.
  • Ten un despregue doado, porque só necesitamos NGINX co módulo correcto e o noso código, e todo funciona inmediatamente.
  • Comunidade grande e sensible.

Non contei en detalle como se fai o enrutamento, resultou ser unha historia moi longa.

Спасибо за внимание!


Vladimir Protasov - OpenResty: converter NGINX nun servidor de aplicacións completo

Fonte: www.habr.com

Engadir un comentario