Wenn Sie eine WSGI Anwendung auf der Tornado läuft, dann gibt es nicht viel Unterschied zwischen Tornado und gunicorn in so viel wie sonst nichts, so lange die WSGI Antrag behandelt wird passieren kann die Anwendung in einem bestimmten Prozess. Im Falle von Gunicorn, weil es nur eine Thread-Bearbeitung von Anfragen und im Fall von Tornado hat, weil die Main-Event-Schleife während dieser Zeit niemals ausgeführt wird, um gleichzeitige Anfragen zu bearbeiten.
Im Fall von Tornado gibt es tatsächlich auch eine versteckte Gefahr.
Da es nur einen Anforderungs-Thread gibt, akzeptiert der Worker-Prozess für Gunicorn immer nur eine Web-Anfrage. Wenn auf dem Server gleichzeitig Anfragen eingehen, werden diese stattdessen von allen anderen verfügbaren Arbeitsprozessen verarbeitet, da sie alle den gleichen Listener-Socket verwenden.
Mit Tornado jedoch bedeutet die Async-Eigenschaft des Layers unter der WSGI-Anwendung, dass mehr als eine Anforderung gleichzeitig von einem Prozess akzeptiert werden kann. Sie werden zunächst verschachtelt, wenn die Anforderungsheader und Inhalte gelesen werden, die Tornado vor dem Aufruf der WSGI-Anwendung in den Speicher liest. Wenn der gesamte Anforderungsinhalt dann gelesen wurde, wird die Kontrolle an die WSGI-Anwendung übergeben, um diese eine Anfrage zu bearbeiten. In der Zwischenzeit wird die gleichzeitige Anforderung, die von demselben Prozess bearbeitet wird, für den die Anforderungsheader und der Inhalt noch nicht gelesen wurden, solange blockiert, wie die WSGI-Anwendung die erste Anforderung verarbeitet.
Jetzt, wenn Sie nur den einen Tornado-Prozess haben, ist dies keine große Sache, da die Anfragen sowieso serialisiert werden, aber wenn Sie den Tornado-Worker-Modus von Gunicorn verwenden, um mehrere Tornado-Worker-Prozesse mit demselben Listener zu ermöglichen Steckdosen das kann ziemlich schlecht sein.Dies liegt daran, dass die gierige Natur der einzelnen Prozesse, die aus der asynchronen Schicht resultieren, bedeutet, dass Anforderungen in einem Prozess blockiert werden können, wenn es einen anderen Arbeitsprozess gegeben haben könnte, der dies hätte tun können.
Zusammenfassend, für einen einzigen Tornado-Webserver-Prozess stecken Sie fest und können nur eine Anfrage gleichzeitig bearbeiten. In Gunicorn können Sie mehrere Worker-Prozesse haben, damit Anfragen gleichzeitig behandelt werden können. Verwenden Sie jedoch ein Multi-Prozess-Setup mit Tornado, und Sie riskieren, dass Anforderungen blockiert werden.
Also Tornado kann recht gut für sehr kleine benutzerdefinierte WSGI-Anwendung, wo sie nicht viel tun und so ist die Antwort sehr schnell, aber es kann leiden, wo Sie lange laufende Anforderungen unter einer blockierenden WSGI-Anwendung laufen. Gunicorn wird daher besser sein, da es die Fähigkeit besitzt, gleichzeitige Anfragen zu bearbeiten. Da Gunicorn jedoch single-threaded ist und mehrere Worker-Prozesse benötigt, wird es viel mehr Speicher benötigen.
Also beide haben Kompromisse und in einigen Fällen können Sie besser mit einem WSGI-Server, der Nebenläufigkeit durch Multithreading sowie mehrere Worker-Prozesse bietet. Auf diese Weise können Sie gleichzeitige Anforderungen verarbeiten, die Speicherauslastung jedoch nicht durch die Verwendung vieler Worker-Prozesse ausräumen. Gleichzeitig müssen Sie die Anzahl der Threads pro Prozess mit mehreren Prozessen ausgleichen, um nicht übermäßig von den Auswirkungen der GIL in einer CPU-schweren Anwendung betroffen zu sein.
Auswahlmöglichkeiten für WSGI-Server mit Multithreading-Fähigkeiten sind mod_wsgi, uWSGI und Kellnerin. Für Kellnerin sind Sie jedoch auf einen einzelnen Arbeitsprozess beschränkt.
In allem, was der beste WSGI-Server ist, hängt sehr viel von den Besonderheiten Ihrer Webanwendung ab. Es gibt keinen WSGI-Server, der in allem der Beste ist.
Vielen Dank für Ihre ausführliche Erklärung. Im Fall von C10K Problem wird die WSGI mit Gunicorn besser sein. Könnten Sie mir mehr Licht dazu sagen: "Dies liegt daran, dass die gierige Natur der einzelnen Prozesse, die aus der asynchronen Schicht resultieren, dazu führt, dass Anforderungen in einem Prozess blockiert werden, wenn es einen anderen Arbeitsprozess gegeben hätte Prozess teilen den gleichen Listenport, warum kann kein anderer Worker die eingehenden Anfragen verarbeiten? – schemacs
Da der erste Worker-Prozess die Socket-Verbindung bereits akzeptiert hat und beginnt, Daten daraus zu lesen. Ein anderer Prozess kann die Verbindung zu diesem Zeitpunkt nicht übernehmen. Es ist ein ähnliches Problem wie bei einem WSGI-Modul, das für das Einbetten in nginx geschrieben wurde, wie in http://blog.dscpl.com.au/2009/05/blocking-requests-and-nginx-version-of.html beschrieben –
In Bezug auf mythische C10K, hilft das Kleben von nginx auf Gunicorn mit einer WSGI-Anwendung nicht viel damit. Die Anzahl der gleichzeitigen Anfragen, die gunicorn verarbeiten kann, ist immer noch begrenzt durch die Anzahl der Prozesse, die Sie in den Speicher einpassen können. Die Tatsache, dass es viel mehr Arbeitsprozesse als Prozessorkerne gibt, kann sich in einigen Fällen nachteilig auf die Leistung auswirken, da Pythons GIL funktioniert ein Multiprozessorsystem. –