"Don`t block the event loop..." - diesen Satz haben Sie wahrscheinlich schon oft gehört... Das wundert mich nicht, denn er ist eine der wichtigsten Annahmen bei der Arbeit mit Node. Aber es gibt noch ein zweites "Ding", das Sie nicht blockieren sollten - den Worker Pool. Wenn er vernachlässigt wird, kann er erhebliche Auswirkungen auf die Leistung der Anwendung und sogar auf ihre Sicherheit haben.
Fäden
Das Wichtigste ist: Es gibt zwei Arten von Threads in Node.js: Haupt-Thread - dieser wird von Ereignis-Schleifeund Arbeitskräfte-Pool (Thread-Pool) - das ist der Pool von Threads -
Dank an libuv. Jede von ihnen hat eine andere Aufgabe. Das Ziel der ersten ist es, nicht blockierende E/A-Operationen zu verarbeiten, und die zweite ist für CPU-intensive Arbeit und auch blockierende E/A zuständig.
Aber was ist ein Thread und wie unterscheidet er sich von einem Prozess? Es gibt mehrere Unterschiede, aber der wichtigste für uns ist, wie ihnen der Speicher zugewiesen wird. Sie können sich einen Prozess wie eine Anwendung vorstellen. Innerhalb jedes Prozesses gibt es einen Teil des Speichers, der nur für diesen Prozess bestimmt ist. Ein Prozess hat also keinen Zugriff auf den Speicher des anderen, und diese Eigenschaft gewährleistet eine hohe Sicherheit. Um die Kommunikation zwischen den Prozessen herzustellen, müssen wir einige Arbeit leisten. Threads sind anders. Threads laufen innerhalb eines Prozesses und teilen sich denselben Speicher, so dass es überhaupt kein Problem mit der gemeinsamen Nutzung von Daten durch Threads gibt.
Ein Punkt verursacht jedoch ein Problem. Es ist die so genannte Race Condition. Die Threads können gleichzeitig ablaufen, woher wissen wir also, welcher zuerst endet? Es kann passieren, dass beim ersten Mal die erste Operation zuerst beendet wird, und beim nächsten Mal ist es vielleicht umgekehrt und die zweite Operation endet vor der ersten. Stellen Sie sich vor, Sie arbeiten mit Schreib-/Leseoperationen unter solchen Bedingungen! Ein Albtraum! Es ist manchmal sehr schwer, korrekte Code in einer Multithreading-Umgebung.
Außerdem haben die Multi-Thread-Sprachen einen großen Speicher-Overhead, weil sie für jede Anfrage einen eigenen Thread erstellen; wenn Sie also 1000 Anfragen aufrufen wollen, erstellen sie 1000 Threads.
Wie geht man mit einem solchen Problem um? Verwenden Sie stattdessen einen einzigen Faden! Und das ist es, was Knotenpunkt bietet Ihnen.
Als JavaScript Entwickler Ich möchte Sie ermutigen, sich die Film
in dem Bart Belder das Konzept der Ereignisschleife anschaulich erläutert. Das obige Diagramm ist seiner Präsentation entnommen. Und wenn Sie diese Begriffe überhaupt nicht kennen, können Sie beide Knotenpunkt und Libuv haben eine ausgezeichnete Dokumentation 🙂
Über das Blockieren
Unter JavaScript Entwicklung Industrie sagen sie das, weil Knotenpunkt single-threaded und non-blocking ist, können Sie mit denselben Ressourcen eine höhere Gleichzeitigkeit erreichen als mit multi-threaded Lösungen. Das ist wahr, aber es ist nicht so schön und einfach, wie es scheinen mag.
Seit Node.js single-threaded ist (JS-Teil), werden CPU-intensive Aufgaben alle laufenden Anfragen blockieren, bis die jeweilige Aufgabe abgeschlossen ist. Es ist also wahr, dass in Node.js können Sie jede Anfrage blockieren, nur weil eine von ihnen eine blockierende Anweisung enthält. Blockierender Code bedeutet, dass es länger als ein paar Millisekunden dauert, bis er fertig ist. Verwechseln Sie aber lange Antwortzeiten nicht mit Blockierung. Die Antwort der Datenbank kann sehr lange dauern, aber sie blockiert Ihren Prozess (die Anwendung) nicht.
Blockierende Methoden werden synchron ausgeführt, nicht blockierende Methoden werden asynchron ausgeführt.
Wie können Sie Ihre Ereignisschleife verlangsamen (oder blockieren)?
- anfällige Regex - ein anfälliger regulärer Ausdruck ist derjenige, bei dem Ihre Engine für reguläre Ausdrücke exponentiell viel Zeit benötigt; Sie können mehr darüber lesen hier,
- JSON-Operationen für große Objekte,
- unter Verwendung synchroner APIs von Knotenpunkt Kernmodule anstelle von asynchronen Versionen; alle E/A-Methoden in der Node.js-Standardbibliothek bieten auch ihre asynchronen Versionen,
- andere Programmierfehler, wie synchrone Endlosschleifen.
Ist es in diesem Fall, da der Worker Pool einen Pool von Threads verwendet, möglich, auch diese zu blockieren? Leider ja 🙁. Knotenpunkt basiert auf einer Philosophie ein Thread für viele Kunden.
Nehmen wir an, dass eine bestimmte Aufgabe, die von einem bestimmten Worker ausgeführt wird, sehr komplex ist und mehr Zeit für ihre Erledigung benötigt. Infolgedessen ist der Worker blockiert und kann nicht für die Ausführung anderer anstehender Aufgaben verwendet werden, bis seine Anweisungen ausgeführt sind. Wie Sie wahrscheinlich schon erraten haben, kann dies die Leistung beeinträchtigen. Sie können solche Probleme vermeiden, indem Sie die Schwankungen bei den Task-Zeiten durch die Verwendung von Task-Partitionierung minimieren.
Schlussfolgerung
Vermeiden Sie das Blockieren, das ist sicher. Wenn Sie nur können, wählen Sie immer asynchrone Versionen der Standardbibliotheks-APIs. Andernfalls kann der Client nach der Ausführung Ihrer Anwendung auf mehrere Probleme stoßen, angefangen beim verminderten Durchsatz bis hin zum vollständigen Rückzug, was aus Sicht des Benutzers fatal ist.
Lesen Sie mehr:
Warum Sie (wahrscheinlich) Typescript verwenden sollten
Wie kann man ein Projekt nicht durch schlechte Programmierpraktiken zerstören?
Strategien zum Abrufen von Daten in NextJS