OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandelnWir veröffentlichen erneut die Zusammenfassung des Vortrags von der Konferenz HighLoad++ 2016, die vom 7. bis 8. November letzten Jahres in Skolkovo bei Moskau stattfand. Wladimir Protasow berichtet, wie man die Funktionalität von NGINX mit OpenResty und Lua erweitern kann.

Hallo zusammen, ich heiße Wladimir Protasow und arbeite bei Parallels. Ich möchte ein wenig über mich erzählen. Drei Viertel meines Lebens schreibe ich Code. Ich bin Programmierer durch und durch: manchmal sehe ich im Schlaf Code. Ein Viertel meines Lebens widme ich der industriellen Entwicklung, dem Schreiben von Code, der direkt in die Produktion geht. Der Code, den einige von Ihnen verwenden, ohne es zu wissen.

Um zu verstehen, wie problematisch die Situation war. Als ich noch ein kleiner Junior war, kam ich und erhielt solche zwei Terabyte großen Datenbanken. Heutzutage haben alle hier Highload. Ich ging zu Konferenzen und fragte: „Hey Leute, erzählt mir, ihr habt Big Data, das ist großartig? Wie groß sind eure Datenbanken?“ Sie antworteten: „Wir haben 100 Gigabyte!“ Ich dachte: „Cool, 100 Gigabyte!“ und versuchte, meine Miene zu wahren. Du denkst, ja, die Jungs sind beeindruckend, und dann kommst du zurück und kämpfst mit diesen Multi-Terabyte-Datenbanken. Und das, während ich noch ein Junior war. Könnt ihr euch vorstellen, wie das gewesen wäre?

Ich kenne mehr als 20 Programmiersprachen. Das ist etwas, womit ich mich während meiner Arbeit auseinandersetzen musste. Dir wird Code in Erlang, C, C++, Lua, Python, Ruby und anderen Sprachen gegeben, und du musst alles umsetzen. Insgesamt war es notwendig. Die genaue Anzahl habe ich nicht ermitteln können, aber irgendwo ist die Zahl von 20 verloren gegangen.

Da alle Anwesenden wissen, was Parallels ist und was wir tun, werde ich nicht darüber sprechen, wie großartig wir sind und was wir machen. Ich möchte nur erwähnen, dass wir 13 Büros weltweit haben, über 300 Mitarbeiter und unsere Entwicklung in Moskau, Tallinn und Malta stattfindet. Wenn gewünscht, kann man auch nach Malta ziehen, falls es im Winter zu kalt ist und man die Rückseite wärmen möchte.

Speziell unsere Abteilung programmiert in Python 2. Wir sind im Geschäft und haben keine Zeit, modische Technologien zu implementieren, also leiden wir. Wir nutzen Django, weil es alles bietet und wir das Überflüssige einfach weggelassen haben. Außerdem verwenden wir MySQL, Redis und NGINX. Und wir haben viele andere coole Dinge. Wir haben MongoDB, bei uns laufen Kaninchen herum, wir haben so ziemlich alles — aber das ist nicht mein Bereich, damit beschäftige ich mich nicht.

OpenResty

Ich habe über mich selbst gesprochen. Lassen Sie uns klären, worüber ich heute sprechen werde:

  • Was ist OpenResty und wozu benötigt man das?
  • Warum sollte man noch ein weiteres Rad erfinden, wenn wir Python, NodeJS, PHP, Go und andere großartige Technologien haben, mit denen alle zufrieden sind?
  • Und ein paar Beispiele aus dem Leben. Ich musste meinen Vortrag stark kürzen, weil er ursprünglich 3,5 Stunden lang war, daher werden die Beispiele spärlich sein.

OpenResty ist NGINX. Damit haben wir einen vollwertigen Webserver, der gut geschrieben ist und schnell arbeitet. Ich denke, die meisten von uns nutzen NGINX in der Produktion. Jeder von Ihnen weiß, dass es schnell und großartig ist. Es bietet eine tolle synchrone Eingabe/Ausgabe, deshalb müssen wir nichts selbst entwickeln, so wie es in Python mit gevent gemacht wurde. Gevent ist großartig, aber wenn Sie C-Code schreiben und etwas schiefläuft, werden Sie verrückt beim Debuggen mit gevent. Ich hatte die Erfahrung: Es hat zwei ganze Tage gedauert, um herauszufinden, was da schiefgegangen ist. Wenn nicht jemand zuvor Wochen daran gearbeitet hätte, das Problem gefunden, es im Internet dokumentiert und Google das entdeckt hätte, wären wir komplett durchgedreht.

NGINX verfügt bereits über Caching und statische Inhalte. Sie müssen sich keine Gedanken darüber machen, wie das richtig eingerichtet wird, damit nichts ins Stocken gerät und Sie keine Deskriptoren verlieren. Nginx lässt sich sehr einfach bereitstellen; Sie müssen sich keine Gedanken machen, was Sie verwenden sollen – WSGI, PHP-FPM, Gunicorn, Unicorn. Nginx wird installiert, den Admins übergeben, die wissen, wie man damit umgeht. Nginx bearbeitet Anfragen strukturiert. Darüber werde ich später noch ein wenig mehr erzählen. Kurz gesagt, es gibt eine Phase, in der es die Anfrage angenommen hat, eine, in der es verarbeitet hat, und eine, in der der Inhalt an den Benutzer geliefert wird.

Nginx ist großartig, aber es gibt ein Problem: Es ist nicht flexibel genug, auch mit all den großartigen Funktionen, die in die Konfiguration integriert wurden, trotz der Anpassungsmöglichkeiten. Diese Leistung reicht nicht aus. Deshalb haben die Leute von Taobao vor etwa acht Jahren Lua eingebaut. Was bringt das?

  • Größe. Es ist klein. LuaJIT hat einen Overhead von etwa 100-200 Kilobyte im Speicher und einen minimalen Performance-Overhead.
  • Geschwindigkeit. Der LuaJIT-Interpreter ist in vielen Situationen vergleichbar mit C, in einigen Aspekten übertrifft er Java, in anderen liegt er zurück. Eine Zeit lang galt er als state of the art, als der beeindruckendste JIT-Compiler. Heutzutage gibt es leistungsfähigere, aber sie sind sehr schwergewichtig, wie beispielsweise V8. Einige JS-Interpreter und der Java HotSpot sind an bestimmten Stellen schneller, verlieren aber in anderen immer noch.
  • Einfach zu erlernen. Wenn Sie beispielsweise eine Codebasis in Perl haben und nicht Booking sind, werden Sie keine Perl-Programmierer finden. Denn sie gibt es nicht mehr, sie sind alle weg, und sie zu schulen ist langwierig und kompliziert. Wenn Sie Programmierer in einer anderen Sprache wollen, müssen diese möglicherweise ebenfalls umgeschult oder gefunden werden. Bei Lua geht es einfach. Lua lässt sich von jedem Junior in drei Tagen erlernen. Ich habe etwa zwei Stunden gebraucht, um mich einzuarbeiten. Nach zwei Stunden schrieb ich bereits Code für die Produktion. Etwa eine Woche später war er direkt in der Produktion.

So sieht das Endergebnis aus:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Hier gibt es viel zu entdecken. In OpenResty wurden viele Module zusammengefasst, sowohl eigene als auch von Engines. Und alles ist fertig — einfach deployen und es läuft.

Beispiele

Genug der Lyrik, kommen wir zum Code. Hier ist ein kleines Hello World:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Was gibt es hier? Dies ist ein endjinseitiger Standort. Wir machen uns keinen Stress, schreiben kein eigenes Routing und verwenden nichts Fertiges – wir haben bereits etwas in NGINX, wir leben gut und entspannt.

content_by_lua_block – das ist ein Block, der besagt, dass wir Inhalte mithilfe eines Lua-Skripts ausliefern. Wir nehmen die endjinseitige Variable remote_addr und stecken sie in string.format. Das ist dasselbe wie sprintf, nur auf Lua, nur richtig. Und wir geben es dem Kunden aus.

Das Ergebnis sieht so aus:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Aber zurück zur Realität. In der Produktion wird niemand Hello World bereitstellen. Unsere Anwendung greift normalerweise auf eine Datenbank oder ähnliches zu und wartet die meiste Zeit auf eine Antwort.

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Sie sitzt einfach da und wartet. Das ist nicht ideal. Wenn 100.000 Benutzer kommen, wird es sehr schwierig. Daher lass uns als Beispiel eine einfache Anwendung skizzieren. Wir werden nach Bildern suchen, zum Beispiel von Katzen. Aber wir werden nicht einfach so suchen, wir werden die Schlüsselwörter erweitern und, wenn der Benutzer nach „Kätzchen“ sucht, finden wir für ihn Katzen, Flauschtiere und ähnliches. Zuerst müssen wir die Anfragedaten im Backend erfassen. So sieht das aus:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Zwei Zeilen ermöglichen es uns, die GET-Parameter abzurufen, ganz ohne Schwierigkeiten. Danach holen wir die Informationen, beispielsweise über einen SQL-Befehl aus einer Datenbank mit einer Tabelle für das Schlüsselwort und die Erweiterung. Ganz einfach. So sieht das aus:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir binden die Bibliothek resty.mysql, die bereits in unserem Paket enthalten ist, ein. Wir müssen nichts installieren, alles ist bereit. Wir geben an, wie wir uns verbinden und führen die SQL-Abfrage durch:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Hier wird es ein wenig gruselig, aber alles funktioniert. Hier zeigt die Zahl 10 das Limit an. Wir ziehen 10 Einträge, wir sind faul und möchten nicht mehr anzeigen. In SQL habe ich das Limit vergessen.

Dann suchen wir die Bilder zu allen Anfragen. Wir sammeln eine Reihe von Anfragen und füllen eine Lua-Tabelle, die reqs, genannt wird, und führen ngx.location.capture_multi.

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

aus. Alle diese Anfragen laufen parallel und wir erhalten die Antworten. Die Arbeitszeit entspricht der Antwortzeit der langsamsten Anfrage. Wenn alle innerhalb von 50 Millisekunden antworten und wir hundert Anfragen gesendet haben, kommt die Antwort nach 50 Millisekunden.

Da wir faul sind und keine HTTP-Verarbeitung und Caching schreiben möchten, lassen wir NGINX alles für uns erledigen. Wie Sie gesehen haben, gab es eine Anfrage an url/fetch, genau das:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir machen einen einfachen proxy_pass, wir geben an, wo der Cache gespeichert werden soll, wie das funktioniert, und bei uns läuft alles.

Aber das reicht nicht, wir müssen die Daten auch an den Benutzer zurückgeben. Die einfachste Idee ist, alles in JSON zu serialisieren, ganz unkompliziert, in zwei Zeilen. Wir geben den Content-Type zurück, wir geben JSON zurück.

Aber es gibt eine Schwierigkeit: Der Benutzer möchte kein JSON lesen. Wir müssen Frontend-Entwickler einbeziehen. Manchmal möchten wir das anfangs nicht tun. Und die SEO-Spezialisten sagen, dass es ihnen egal ist, wenn wir nach Bildern suchen. Aber wenn wir bestimmten Content ausgeben, werden sie sagen, dass unsere Inhalte von den Suchmaschinen nicht indexiert werden.

Was tun wir damit? Natürlich werden wir dem Benutzer HTML zurückgeben. Manuell generieren ist nicht optimal, also möchten wir Vorlagen verwenden. Dafür gibt es die Bibliothek lua-resty-template.

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Sie haben wahrscheinlich die drei furchtbaren Buchstaben OPM gesehen. OpenResty kommt mit seinem eigenen Paketmanager, über den man viele verschiedene Module installieren kann, darunter lua-resty-template. Dies ist eine einfache Template-Engine, die den Django-Templates ähnelt. Dort kann man Code schreiben und Variablen ersetzen.

Am Ende wird alles ungefähr so aussehen:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir haben die Daten genommen und die Vorlage erneut in zwei Zeilen gerendert. Der Benutzer ist zufrieden, er hat Kätzchen bekommen. Da wir die Anfrage erweitert haben, hat er zusätzlich ein See-Eichhörnchen gefunden. Vielleicht hat er genau danach gesucht, konnte aber seine Anfrage nicht korrekt formulieren.

Alles ist großartig, aber wir sind noch in der Entwicklungsphase und möchten den Benutzern vorerst nichts zeigen. Lassen Sie uns eine Authentifizierung einrichten. Um dies zu tun, schauen wir uns an, wie NGINX die Anfrage im Kontext von OpenResty verarbeitet:

  • Die erste Phase — Access, wenn der Benutzer gerade gekommen ist und wir ihn anhand der Header, der IP-Adresse und anderer Daten analysiert haben. Wir können ihn sofort abweisen, wenn er uns nicht gefällt. Dies kann zur Authentifizierung verwendet werden oder, falls wir eine große Anzahl an Anfragen erhalten, können wir sie in dieser Phase leicht ablehnen.
  • rewrite. Wir schreiben einige Daten der Anfrage um.
  • content. Wir liefern den Inhalt an den Benutzer aus.
  • headers filter. Wir ändern die Header der Antwort. Wenn wir verwendet haben proxy_pass, können wir einige Header umschreiben, bevor wir sie dem Benutzer zurückgeben.
  • body filter. Wir können den Body ändern.
  • log — Protokollierung. Wir können Protokolle in Elasticsearch ohne zusätzliche Schicht schreiben.

Unsere Authentifizierung wird ungefähr so aussehen:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir fügen dies in den vorher beschriebenen locationein und integrieren dort diesen Code:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir prüfen, ob wir ein Cookie-Token haben. Wenn nicht, leiten wir zur Authentifizierung weiter. Nutzer sind schlau und könnten darauf kommen, das Cookie-Token zu setzen. Deshalb speichern wir es zusätzlich in Redis:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Der Code zur Arbeit mit Redis ist sehr einfach und unterscheidet sich nicht von anderen Sprachen. Dabei ist der Input/Output, sowohl dort als auch hier, nicht blockierend. Wenn Sie synchronen Code schreiben, funktioniert es asynchron. Etwa wie bei gevent, nur gut umgesetzt.

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Lassen Sie uns die Authentifizierung durchführen:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Wir geben an, dass wir den Körper der Anfrage lesen müssen. Wir erhalten die POST-Argumente und überprüfen, ob Benutzername und Passwort korrekt sind. Wenn sie falsch sind, leiten wir zur Authentifizierung weiter. Wenn sie richtig sind, speichern wir das Token in Redis:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Vergessen Sie nicht, das Cookie zu setzen, das geschieht ebenfalls in zwei Zeilen:

OpenResty: NGINX in einen vollwertigen Anwendungsserver verwandeln

Dies ist ein einfaches, theoretisches Beispiel. Natürlich werden wir keinen Dienst erstellen, der den Menschen Katzenbilder zeigt. Obwohl, wer weiß das schon. Lassen Sie uns daher durchgehen, was in der Produktion möglich ist.

  • Minimalistisches Backend. Manchmal müssen wir im Backend nur eine kleine Menge an Daten ausgeben: an manchen Stellen einen Datumswert einsetzen, an anderen Orten eine Liste anzeigen, sagen, wie viele Benutzer gerade auf der Website sind, einen Zähler oder Statistiken anhängen. Etwas in dieser Art. Kleine Fragmente lassen sich sehr leicht umsetzen. Das geht schnell, unkompliziert und effizient.
  • Datenvorverarbeitung. Manchmal möchten wir Werbung auf unserer Seite integrieren, und diese Werbung beziehen wir über API-Anfragen. Das lässt sich genau hier sehr einfach realisieren. Wir belasten unser Backend, das ohnehin schon stark beansprucht wird, nicht zusätzlich. Stattdessen können wir die Informationen hier einsammeln. Wir können einige JS-Skripte zusammensetzen oder, im Gegenteil, etwas auftrennen und vorverarbeiten, bevor wir es dem Benutzer bereitstellen.
  • Fassade für Mikrodienste. Das ist ebenfalls ein sehr guter Anwendungsfall, den ich umgesetzt habe. Davor arbeitete ich bei der Firma Tenzor, die elektronische Berichterstattung anbietet und etwa die Hälfte der Unternehmen im Land unterstützt. Wir haben einen Service entwickelt, bei dem viele Vorgänge mithilfe desselben Mechanismus realisiert wurden: Routing, Authentifizierung und anderes.
    OpenResty kann als Klebstoff für Ihre Mikrodienste verwendet werden, der einen einheitlichen Zugang zu allem und eine einheitliche Schnittstelle bietet. Da Mikrodienste so geschrieben werden können, dass Sie hier Node.js, dort PHP, hier Python und dort eine Lösung auf Erlang haben, verstehen wir, dass wir nicht den gleichen Code überall neu schreiben möchten. Daher kann OpenResty im Frontend eingesetzt werden.
  • Statistik und Analytik. Normalerweise steht NGINX am Eingang, und alle Anfragen laufen über ihn. Genau an dieser Stelle lässt sich sehr gut sammeln. Man kann sofort etwas zählen und irgendwo hin senden, wie zum Beispiel an Elasticsearch, Logstash oder einfach in ein Protokoll schreiben und später woanders hin schicken.
  • Multiplayer-Systeme. Zum Beispiel lassen sich Online-Spiele ebenfalls sehr gut umsetzen. Heute wird Alexander Gladys in Kapstadt darüber sprechen, wie man schnell ein Multiplayer-Spiel mit OpenResty prototypisiert.
  • Anfragefilterung (WAF). Heutzutage ist es angesagt, verschiedene Web Application Firewalls einzurichten, und es gibt viele Dienste, die diese anbieten. Mit OpenResty können Sie sich eine Web Application Firewall erstellen, die Anfragen einfach und effizient nach Ihren Anforderungen filtert. Wenn Sie Python verwenden, wissen Sie, dass PHP Ihnen nicht injiziert werden kann, es sei denn, Sie spawnen es zufällig irgendwo aus der Konsole. Sie wissen, dass Sie MySQL und Python haben. Vielleicht versuchen sie hier, einen Directory Traversal durchzuführen und irgendetwas in die Datenbank zu injizieren. Daher können Sie verdächtige Anfragen schnell und kostengünstig gleich am Frontend filtern.
  • Gemeinschaft. Da OpenResty auf NGINX basiert, gibt es einen zusätzlichen Vorteil – das NGINX-Community. Es ist sehr groß, und ein erheblicher Teil der Fragen, die Ihnen zunächst in den Sinn kommen, wurde bereits von der NGINX-Community gelöst.

    Lua-Entwickler. Gestern sprach ich mit den Teilnehmern des HighLoad++-Schultages und hörte, dass nur Tarantool in Lua geschrieben ist. Das ist nicht korrekt; es gibt viele Projekte in Lua. Beispiele sind: OpenResty, der XMPP-Server Prosody, die Spiel-Engine Love2D, Lua-Skripte in Warcraft und anderswo. Es gibt viele Lua-Entwickler, und die Community ist groß und hilfsbereit. Alle meine Fragen zu Lua wurden innerhalb weniger Stunden beantwortet. Wenn man in die Mailingliste schreibt, folgen innerhalb weniger Minuten zahlreiche Antworten, die alles erklären. Das ist wirklich toll. Leider gibt es nicht überall so eine freundliche Community.
    Für OpenResty gibt es ein GitHub-Repository, wo man ein Issue erstellen kann, falls etwas nicht funktioniert. Es gibt eine Mailingliste bei Google Groups, um allgemeine Fragen zu besprechen, und einen chinesischen Newsletter – falls Ihr Englisch nicht ausreicht, Sie aber Chinesisch sprechen.

Ergebnisse

  • Ich hoffe, ich konnte vermitteln, dass OpenResty ein sehr komfortables Framework ist, das speziell für das Web entwickelt wurde.
  • Es hat eine niedrige Einstiegshürde, da der Code ähnlich ist wie der, den wir verwenden, und die Sprache ist recht einfach und minimalistisch.
  • Es bietet asynchrones I/O ohne Callbacks, sodass wir nicht den unübersichtlichen Code haben, den wir manchmal in NodeJS schreiben.
  • Es lässt sich einfach bereitstellen, da wir nur NGINX mit dem benötigten Modul und unseren Code benötigen, und alles funktioniert sofort.
  • Eine große und hilfsbereite Community.

Ich habe nicht im Detail erklärt, wie das Routing funktioniert, da das sehr langwierig geworden wäre.

Vielen Dank für Ihre Aufmerksamkeit!

Video abspielen

Wladimir Protasow — OpenResty: Wir verwandeln NGINX in einen vollwertigen Anwendungsserver.

Quelle: habr.com
Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster