Es gibt keine Silberkugel
In der Praxis kommt es darauf an ...
tl; dr - einfache Lösung, verwenden Sie Nginx ...
Blockierung:
Beispielsweise verwendet Apache standardmäßig ein Blockierungsschema, bei dem der Prozess für jede Verbindung verzweigt wird. Das bedeutet, dass jede Verbindung ihren eigenen Speicherplatz benötigt und der Aufwand für die Kontextumschaltung mit zunehmender Anzahl von Verbindungen zunimmt. Der Vorteil ist jedoch, dass nach dem Schließen einer Verbindung der Kontext entsorgt werden kann und der gesamte Speicher leicht abgerufen werden kann.
Ein Multithread-Ansatz wäre insofern ähnlich, als der Overhead der Kontextumschaltung mit der Anzahl der Verbindungen zunimmt, in einem gemeinsam genutzten Kontext jedoch speichereffizienter sein kann. Das Problem bei einem solchen Ansatz ist, dass es schwierig ist, den gemeinsam genutzten Speicher auf sichere Weise zu verwalten. Die Ansätze zur Überwindung von Speichersynchronisationsproblemen umfassen häufig ihren eigenen Overhead. Beispielsweise kann das Sperren des Hauptthreads bei CPU-intensiven Lasten einfrieren, und die Verwendung unveränderlicher Typen führt zu einer Menge unnötigem Kopieren von Daten.
AFAIK verwendet im Allgemeinen einen Multiprozess-Ansatz auf einem blockierenden HTTP-Server, da es sicherer / einfacher ist, Speicher auf sichere Weise zu verwalten / wiederherzustellen. Die Speicherbereinigung wird zu einem Problem, wenn die Wiederherstellung des Speichers so einfach ist wie das Stoppen eines Prozesses. Für lang laufende Prozesse (dh einen Daemon) ist diese Eigenschaft besonders wichtig.
Während der Overhead für die Kontextumschaltung bei einer kleinen Anzahl von Mitarbeitern unbedeutend erscheint, werden die Nachteile relevanter, wenn die Last auf Hunderte bis Tausende von gleichzeitigen Verbindungen skaliert. Im besten Fall skaliert die Kontextumschaltung O (n) auf die Anzahl der anwesenden Arbeitnehmer, in der Praxis ist dies jedoch höchstwahrscheinlich schlimmer.
Wenn Server, die das Blockieren verwenden, möglicherweise nicht die ideale Wahl für schwere E / A-Lasten sind, sind sie ideal für CPU-intensive Arbeit, und die Nachrichtenübermittlung wird auf ein Minimum beschränkt.
Nicht blockierend:
Nicht blockierend wäre so etwas wie Node.js oder Nginx. Diese sind insbesondere für die Skalierung auf eine viel größere Anzahl von Verbindungen pro Knoten unter E / A-intensiver Last bekannt. Sobald die Leute die Obergrenze der Thread- / prozessbasierten Server erreicht hatten, begannen sie im Grunde, nach alternativen Optionen zu suchen. Dies wird auch als C10K-Problem bezeichnet (dh die Fähigkeit, 10.000 gleichzeitige Verbindungen zu verarbeiten).
Nicht blockierende asynchrone Server haben im Allgemeinen viele Merkmale mit einem Multi-Threaded-with-Locking-Ansatz gemeinsam, da Sie vorsichtig sein müssen, um CPU-intensive Lasten zu vermeiden, da Sie den Haupt-Thread nicht überlasten möchten. Der Vorteil besteht darin, dass der durch die Kontextumschaltung entstehende Overhead im Wesentlichen entfällt und mit nur einer Kontextnachricht die Weitergabe kein Problem darstellt.
Während es für viele Netzwerkprotokolle möglicherweise nicht funktioniert, funktioniert die zustandslose Natur von HTTPs besonders gut für nicht blockierende Architekturen. Durch die Kombination eines Reverse-Proxys und mehrerer nicht blockierender HTTP-Server können Knoten mit hoher Auslastung identifiziert und umgeleitet werden.
Selbst auf einem Server mit nur einem Knoten enthält das Setup häufig einen Server pro Prozessorkern, um den Durchsatz zu maximieren.
Beide:
Der "ideale" Anwendungsfall wäre eine Kombination aus beiden. Ein Reverse-Proxy an der Vorderseite für Routing-Anforderungen an der Spitze, dann eine Mischung aus blockierenden und nicht blockierenden Servern. Nicht blockierend für E / A-Aufgaben wie das Bereitstellen von statischem Inhalt, Cache-Inhalt und HTML-Inhalt. Blockieren für CPU-schwere Aufgaben wie das Codieren von Bildern / Videos, das Streamen von Inhalten, das Knacken von Zahlen, das Schreiben von Datenbanken usw.
In Ihrem Fall:
Wenn Sie nur Header überprüfen, aber die Anforderungen nicht tatsächlich verarbeiten, beschreiben Sie im Wesentlichen einen Reverse-Proxy. In einem solchen Fall würde ich definitiv einen asynchronen Ansatz wählen.
Ich würde vorschlagen, die Dokumentation für den in Nginx integrierten Reverse-Proxy zu lesen .
Beiseite:
Ich habe den Artikel über den von Ihnen angegebenen Link gelesen und es ist sinnvoll, dass Async eine schlechte Wahl für die jeweilige Implementierung war. Das Problem kann in einer Aussage zusammengefasst werden.
Beim Wechseln zwischen Clients wurde festgestellt, dass der Code zum Speichern und Wiederherstellen von Werten / Status schwierig war
Sie bauten eine staatliche Plattform. In einem solchen Fall würde ein asynchroner Ansatz bedeuten, dass Sie den Status jedes Mal, wenn der Kontext wechselt (dh wenn ein Ereignis ausgelöst wird), ständig speichern / laden müssen. Darüber hinaus leisten sie auf der SMTP-Seite viel CPU-intensive Arbeit.
Es hört sich so an, als hätten sie Async ziemlich schlecht verstanden und infolgedessen viele schlechte Annahmen getroffen.