OpenResty : transformer NGINX en un serveur d'applications à part entière

OpenResty : transformer NGINX en un serveur d'applications à part entièreNous republions la transcription du rapport de la conférence HighLoad ++ 2016, qui s'est tenue à Skolkovo près de Moscou les 7 et 8 novembre de l'année dernière. Vladimir Protasov explique comment étendre les fonctionnalités de NGINX avec OpenResty et Lua.

Bonjour à tous, je m'appelle Vladimir Protasov, je travaille pour Parallels. Je vais vous parler un peu de moi. Je passe les trois quarts de ma vie à écrire du code. Je suis devenu programmeur dans l'âme au sens littéral : je vois parfois du code dans mes rêves. Un quart de la vie est le développement industriel, l'écriture de code qui va directement dans la production. Code que certains d'entre vous utilisent mais ne connaissent pas.

Pour vous faire savoir à quel point c'était mauvais. Quand j'étais un peu junior, je suis arrivé et ils m'ont donné ces bases de données de deux téraoctets. Il est maintenant là pour tout le monde highload. Je suis allé à des conférences et j'ai demandé : « Les gars, dites-moi, avez-vous du big data, est-ce que tout est cool ? Combien de bases avez-vous là-bas ? Ils m'ont répondu : "Nous avons 100 gigaoctets !" J'ai dit: "Cool, 100 gigaoctets!" Et je me suis dit comment sauver proprement le visage de poker. Vous pensez, oui, les gars sont cool, puis vous revenez et bricolez avec ces bases de données de plusieurs téraoctets. Et c'est être un junior. Pouvez-vous imaginer à quel point c'est un succès?

Je connais plus de 20 langages de programmation. C'est ce que j'ai dû comprendre au cours du travail. Ils vous donnent du code en Erlang, en C, en C++, en Lua, en Python, en Ruby, dans autre chose, et vous devez tout couper. En général, je devais. Il n'a pas été possible de calculer le nombre exact, mais quelque part autour de 20, le nombre a été perdu.

Puisque tout le monde ici sait ce qu'est Parallels et ce que nous faisons, je ne parlerai pas de la façon dont nous sommes cool et de ce que nous faisons. Je vous dirai seulement que nous avons 13 bureaux dans le monde, plus de 300 employés, un développement à Moscou, Tallinn et Malte. Si vous le souhaitez, vous pouvez prendre et déménager à Malte, s'il fait froid en hiver et que vous avez besoin de vous réchauffer le dos.

Plus précisément, notre département écrit en Python 2. Nous sommes en affaires et nous n'avons pas le temps d'introduire des technologies à la mode, alors nous souffrons. Nous avons Django, parce qu'il a tout, et nous avons pris l'excédent et l'avons jeté. Aussi MySQL, Redis et NGINX. Nous avons aussi beaucoup d'autres trucs sympas. Nous avons MongoDB, nous avons des lapins qui courent partout, nous n'avons tout simplement rien - mais ce n'est pas le mien, et je ne le fais pas.

OpenResty

J'ai parlé de moi. Voyons de quoi je vais parler aujourd'hui :

  • Qu'est-ce qu'OpenResty et avec quoi est-il consommé ?
  • Pourquoi réinventer la roue quand nous avons Python, NodeJS, PHP, Go et d'autres trucs sympas dont tout le monde est content ?
  • Et quelques exemples concrets. J'ai dû beaucoup réduire le rapport, car je l'ai eu pendant 3,5 heures, il y aura donc peu d'exemples.

OpenResty est NGINX. Grâce à lui, nous avons un serveur Web à part entière, qui est bien écrit, il fonctionne rapidement. Je pense que la plupart d'entre nous utilisent NGINX en production. Vous savez tous qu'il est rapide et cool. Ils y ont créé des E / S synchrones sympas, nous n'avons donc pas besoin de cycler quoi que ce soit de la même manière que gevent a été cyclé en Python. Gevent est cool, génial, mais si vous écrivez du code C et que quelque chose ne va pas avec gevent, vous deviendrez fou en le déboguant. J'avais de l'expérience : il a fallu deux jours entiers pour comprendre ce qui n'allait pas là-bas. Si quelqu'un n'avait pas creusé quelques semaines auparavant, trouvé le problème, l'avait écrit sur Internet et que Google ne l'avait pas trouvé, nous serions devenus complètement fous.

NGINX fait déjà la mise en cache et le contenu statique. Vous n'avez pas à vous soucier de la façon de le faire humainement, pour ne pas ralentir quelque part, pour ne pas perdre de descripteurs quelque part. Nginx est très pratique à déployer, vous n'avez pas besoin de penser à quoi prendre - WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx a été installé, donné aux administrateurs, ils savent comment travailler avec. Nginx traite les demandes de manière structurée. J'en parlerai un peu plus tard. En bref, il a une phase où il vient d'accepter la demande, où il a traité et où il a donné le contenu à l'utilisateur.

Nginx est cool, mais il y a un problème : il n'est pas assez flexible, même avec toutes ces fonctionnalités intéressantes que les gars ont intégrées à la configuration, malgré le fait qu'il peut être personnalisé. Ce pouvoir ne suffit pas. Par conséquent, les gars de Taobao il était une fois, je pense il y a environ huit ans, y ont intégré Lua. Que donne-t-il ?

  • Taille. C'est petit. LuaJIT donne environ 100 à 200 kilo-octets de surcharge de mémoire et une surcharge de performances minimale.
  • vitesse. L'interpréteur LuaJIT est proche de C dans de nombreuses situations, dans certaines situations il perd au profit de Java, dans d'autres il le dépasse. Pendant un certain temps, il a été considéré comme l'état de l'art, le compilateur JIT le plus cool. Maintenant, il y en a des plus cool, mais ils sont très lourds, par exemple, le même V8. Certains interpréteurs JS et Java HotSpot sont plus rapides à certains moments, mais perdent toujours à certains moments.
  • Facile à apprendre. Si vous avez, disons, une base de code Perl et que vous ne réservez pas, vous ne trouverez pas de programmeurs Perl. Parce qu'ils ne sont pas là, ils ont tous été emmenés, et c'est long et difficile de leur enseigner. Si vous voulez des programmeurs pour autre chose, il faudra peut-être aussi les recycler ou les trouver. Dans le cas de Lua, tout est simple. Lua peut être appris par n'importe quel junior en trois jours. Il m'a fallu environ deux heures pour comprendre. Deux heures plus tard, j'écrivais déjà du code en production. Environ une semaine plus tard, il est allé directement à la production et est parti.

En conséquence, cela ressemble à ceci:

OpenResty : transformer NGINX en un serveur d'applications à part entière

Il y en a beaucoup ici. OpenResty a assemblé un tas de modules, à la fois luash et engins. Et vous avez tout prêt - déployé et fonctionnel.

Exemples

Assez de paroles, passons au code. Voici un petit Hello World :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Qu'y a-t-il ? c'est l'emplacement des moteurs. Nous ne nous inquiétons pas, nous n'écrivons pas notre propre routage, nous n'en prenons pas un tout fait - nous l'avons déjà dans NGINX, nous vivons bien et paresseusement.

content_by_lua_block est un bloc qui indique que nous servons du contenu en utilisant un script Lua. On prend une variable engins remote_addr et glissez-le dans string.format. C'est la même chose que sprintf, seulement en Lua, seulement correct. Et nous le donnons au client.

En conséquence, cela ressemblera à ceci:

OpenResty : transformer NGINX en un serveur d'applications à part entière

Mais revenons au monde réel. En production, personne ne déploie Hello World. Notre application va généralement dans la base de données ou ailleurs et la plupart du temps, elle attend une réponse.

OpenResty : transformer NGINX en un serveur d'applications à part entière

Il suffit de s'asseoir et d'attendre. Ce n'est pas très bon. Quand 100.000 XNUMX utilisateurs viennent, c'est très dur pour nous. Par conséquent, utilisons une application simple comme exemple. Nous chercherons des images, par exemple, des chats. Seulement, nous ne nous contenterons pas de rechercher, nous développerons les mots-clés et, si l'utilisateur a recherché "chatons", nous trouverons des chats, des peluches, etc. Nous devons d'abord obtenir les données de la demande sur le backend. Il ressemble à ceci :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Deux lignes vous permettent de récupérer les paramètres GET, sans complications. Ensuite, nous obtenons, par exemple, ces informations à partir d'une base de données avec une table par mot clé et extension à l'aide d'une requête SQL standard. Tout est simple. Il ressemble à ceci :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous connectons la bibliothèque resty.mysql, que nous avons déjà dans le kit. Nous n'avons rien à installer, tout est prêt. Indiquez comment vous connecter et effectuez une requête SQL :

OpenResty : transformer NGINX en un serveur d'applications à part entière

C'est un peu effrayant, mais ça marche. Ici 10 est la limite. On sort 10 disques, on est paresseux, on ne veut plus en montrer. En SQL, j'ai oublié la limite.

Ensuite, nous trouvons des images pour toutes les requêtes. Nous collectons un tas de requêtes et remplissons une table Lua appelée reqs, et fait ngx.location.capture_multi.

OpenResty : transformer NGINX en un serveur d'applications à part entière

Toutes ces demandes vont en parallèle, et les réponses nous sont retournées. Le temps d'exécution est égal au temps de réponse du plus lent. Si nous ripostons tous en 50 millisecondes et que nous envoyons une centaine de requêtes, nous recevrons une réponse en 50 millisecondes.

Puisque nous sommes paresseux et que nous ne voulons pas écrire de gestion et de mise en cache HTTP, nous allons faire en sorte que NGINX fasse tout pour nous. Comme vous l'avez vu, il y a eu une demande de url/fetchle voici:

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous simplifions proxy_pass, spécifiez où mettre en cache, comment le faire, et tout fonctionne pour nous.

Mais cela ne suffit pas, nous devons encore donner les données à l'utilisateur. L'idée la plus simple est de tout sérialiser en JSON, facilement, en deux lignes. Nous donnons Content-Type, nous donnons JSON.

Mais il y a une difficulté : l'utilisateur ne veut pas lire JSON. Nous devons attirer des développeurs front-end. Parfois, nous n'avons pas envie de le faire au début. Oui, et les spécialistes du référencement diront que si nous recherchons des images, ils s'en fichent. Et si on leur donne du contenu, ils diront que nos moteurs de recherche n'indexent rien.

Que dois-je faire avec ça? Bien sûr, nous donnerons à l'utilisateur HTML. Générer avec des poignées n'est pas comme il faut, nous voulons donc utiliser des modèles. Il y a une bibliothèque pour ça lua-resty-template.

OpenResty : transformer NGINX en un serveur d'applications à part entière

Vous devez avoir vu les trois lettres redoutées OPM. OpenResty est livré avec son propre gestionnaire de packages, à travers lequel vous pouvez installer un tas de modules différents, en particulier, lua-resty-template. C'est un moteur de template simple similaire aux templates Django. Là, vous pouvez écrire du code et effectuer des substitutions de variables.

En conséquence, tout ressemblera à ceci:

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous avons pris les données et restitué le modèle en deux lignes. L'utilisateur est heureux, a des chats. Depuis que nous avons élargi la demande, il a également reçu un otarie à fourrure pour chatons. On ne sait jamais, peut-être le cherchait-il, mais il n'arrivait pas à formuler correctement sa demande.

Tout est cool, mais nous sommes en développement et nous ne voulons pas encore montrer aux utilisateurs. Faisons une autorisation. Pour ce faire, voyons comment NGINX gère la requête en termes d'OpenResty :

  • Première phase - accès, lorsque l'utilisateur vient d'arriver, et nous l'avons regardé par en-têtes, par adresse IP, par d'autres données. Vous pouvez immédiatement le couper si nous ne l'aimons pas. Cela peut être utilisé pour l'autorisation, ou si nous recevons beaucoup de demandes, nous pouvons facilement les couper à ce stade.
  • récrire. Réécriture de certaines données de requête.
  • contenu. Nous donnons du contenu à l'utilisateur.
  • filtre d'en-tête. Modifiez les en-têtes de réponse. Si nous avons utilisé proxy_pass, nous pouvons réécrire certains en-têtes avant de le donner à l'utilisateur.
  • filtre corporel. On peut changer de corps.
  • enregistrer - journalisation. Il est possible d'écrire des journaux dans elasticsearch sans couche supplémentaire.

Notre autorisation ressemblera à ceci :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous l'ajouterons à cela location, que nous avons décrit précédemment, et y mettre le code suivant :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous regardons pour voir si nous avons un jeton de cookie. Si ce n'est pas le cas, nous appliquons l'autorisation. Les utilisateurs sont rusés et peuvent deviner qu'un jeton de cookie doit être défini. Par conséquent, nous le mettrons également dans Redis :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Le code pour travailler avec Redis est très simple et ne diffère pas des autres langages. En même temps, toutes les entrées/sorties, ce qui est là, ce qui est ici, ce n'est pas bloquant. Si vous écrivez du code synchrone, il fonctionne de manière asynchrone. Comme avec gevent, seulement bien fait.

OpenResty : transformer NGINX en un serveur d'applications à part entière

Faisons l'autorisation elle-même :

OpenResty : transformer NGINX en un serveur d'applications à part entière

Nous disons que nous devons lire le corps de la requête. Nous recevons des arguments POST, vérifiez que le login et le mot de passe sont corrects. Si incorrect, nous lançons l'autorisation. Et s'ils sont corrects, nous écrivons le jeton sur Redis :

OpenResty : transformer NGINX en un serveur d'applications à part entière

N'oubliez pas de paramétrer le cookie, cela se fait aussi en deux lignes :

OpenResty : transformer NGINX en un serveur d'applications à part entière

L'exemple est simple, spéculatif. Bien sûr, nous ne ferons pas un service qui montre des chats aux gens. Mais qui nous connaît. Passons donc en revue ce qui peut être fait en production.

  • Back-end minimaliste. Parfois, nous devons fournir pas mal de données au backend : quelque part nous devons remplacer la date, quelque part nous devons afficher une sorte de liste, dire combien d'utilisateurs sont sur le site maintenant, visser un compteur ou des statistiques. Quelque chose de si petit. Certaines pièces minimales peuvent être réalisées très facilement. Ce sera rapide, facile et génial.
  • Prétraitement des données. Parfois, nous voulons intégrer des publicités dans notre page, et nous prenons ces publicités avec des requêtes API. C'est très facile à faire ici. Nous ne chargeons pas notre backend, qui travaille déjà dur. Vous pouvez ramasser et récupérer ici. On peut mouler du JS ou au contraire décoller, prétraiter quelque chose avant de le donner à l'utilisateur.
  • Façade pour microservice. C'est aussi un très bon cas, je l'ai mis en œuvre. Avant cela, j'ai travaillé pour Tenzor, une société de reporting électronique qui fournit des rapports à environ la moitié des entités juridiques du pays. Nous avons rendu un service, beaucoup de choses s'y font en utilisant le même mécanisme : routage, autorisation, etc.
    OpenResty peut être utilisé comme colle pour vos microservices afin de fournir un accès unique à tout et une interface unique. Étant donné que les microservices peuvent être écrits de telle manière que vous avez Node.js ici, vous avez PHP ici, vous avez Python ici, il y a quelque chose d'Erlang ici, nous comprenons que nous ne voulons pas réécrire le même code partout. Par conséquent, OpenResty peut être branché à l'avant.

  • Statistiques et analyses. Habituellement, NGINX est à l'entrée et toutes les demandes passent par là. C'est à cet endroit qu'il est très pratique de se recueillir. Vous pouvez immédiatement calculer quelque chose et le jeter quelque part, par exemple, le même Elasticsearch, Logstash, ou simplement l'écrire dans le journal, puis l'envoyer quelque part.
  • Systèmes multi-utilisateurs. Par exemple, les jeux en ligne sont également très bons à faire. Aujourd'hui, au Cap, Alexander Gladysh vous expliquera comment prototyper rapidement un jeu multijoueur à l'aide d'OpenResty.
  • Filtrage des demandes (WAF). Il est maintenant à la mode de créer toutes sortes de pare-feu d'applications Web, de nombreux services les fournissent. Avec l'aide d'OpenResty, vous pouvez vous fabriquer un pare-feu d'application Web, qui filtrera simplement et facilement les requêtes en fonction de vos besoins. Si vous avez Python, vous comprenez que PHP ne vous sera certainement pas injecté, à moins, bien sûr, que vous ne le génériez n'importe où depuis la console. Vous savez que vous avez MySQL et Python. Probablement, ici, ils peuvent essayer de faire une sorte de parcours de répertoire et d'injecter quelque chose dans la base de données. Par conséquent, vous pouvez filtrer les demandes stupides rapidement et à moindre coût dès le début.
  • Communauté. Puisque OpenResty est basé sur NGINX, il a un bonus - c'est Communauté NGINX. Il est très volumineux et la communauté NGINX a déjà répondu à la plupart des questions que vous vous poserez au début.

    Développeurs Lua. Hier, j'ai parlé avec les gars qui sont venus à la journée de formation HighLoad ++ et j'ai entendu dire que seul Tarantool est écrit en Lua. Ce n'est pas le cas, beaucoup de choses sont écrites en Lua. Exemples : OpenResty, serveur Prosody XMPP, moteur de jeu Love2D, Lua est scénarisé dans Warcraft et ailleurs. Il y a beaucoup de développeurs Lua, ils ont une communauté large et réactive. Toutes mes questions Lua ont reçu une réponse en quelques heures. Lorsque vous écrivez à la liste de diffusion, littéralement en quelques minutes, il y a déjà un tas de réponses, elles décrivent quoi et comment, quoi de quoi. C'est bien. Malheureusement, une telle communauté sincère n'est pas partout.
    OpenResty a GitHub, où vous pouvez ouvrir un problème si quelque chose se casse. Il existe une liste de diffusion sur Google Groupes où vous pouvez discuter de problèmes généraux, il existe une liste de diffusion en chinois - on ne sait jamais, peut-être que vous ne parlez pas anglais, mais vous avez des connaissances en chinois.

Les résultats de

  • J'espère avoir été en mesure de transmettre qu'OpenResty est un cadre très pratique conçu pour le Web.
  • Il a un seuil d'entrée bas, puisque le code est similaire à ce que nous écrivons, le langage est assez simple et minimaliste.
  • Il fournit des E/S asynchrones sans rappels, nous n'aurons pas de nouilles comme nous pouvons parfois écrire en NodeJS.
  • Il a un déploiement facile, car nous n'avons besoin que de NGINX avec le bon module et notre code, et tout fonctionne immédiatement.
  • Communauté large et réactive.

Je n'ai pas expliqué en détail comment se fait le routage, cela s'est avéré être une très longue histoire.

Je vous remercie!


Vladimir Protasov - OpenResty : transformer NGINX en un serveur d'applications à part entière

Source: habr.com

Ajouter un commentaire