Wir haben eine sehr komplexe Django-Anwendung, die derzeit von apache / mod_wsgi und auf mehreren AWS EC2-Instanzen hinter einem AWS ELB Load Balancer. Client-Anwendungen interagieren mit dem Server mit AJAX. Sie fragen den Server regelmäßig ab, um Benachrichtigungen abzurufen und Updates zu ihrem Zustand. Wir möchten die Umfrage entfernen und ersetzen es mit "push", mit Web-Sockets.
Weil beliebige Instanzen Web Socket-Anforderungen von Clients verarbeiten und halten Sie auf diese Web-Sockets, und weil wir Daten zu schieben möchten Clients, die sich möglicherweise nicht in derselben Instanz befinden, die die Quelle bereitstellt Daten für den Push, wir brauchen eine Möglichkeit, Daten zu den entsprechenden zu routen Instanz und dann von dieser Instanz an das entsprechende Client-Web Sockel.
Wir stellen fest, dass Apache / mod_wsgi nicht gut mit Web Sockets und spielen plane, diese Komponenten durch nginx / gunicorn zu ersetzen und benutze die Gevent-Websocket-Arbeiter. Wenn jedoch einer von mehreren Worker-Prozessen Empfangen von Anfragen von Clients, um einen Web-Socket einzurichten, und wenn der Lebenszeit der Arbeiterprozesse wird vom Haupt-Gunicorn kontrolliert Prozess, ist es nicht klar, wie andere Arbeitsprozesse oder in der Tat Non-Gunicorn-Prozesse können Daten an diese Web-Sockets senden.
Ein spezieller Fall ist dieser: Ein Benutzer, der eine HTTP-Anfrage absetzt, ist gerichtet auf eine EC2-Instanz (Host) und das gewünschte Verhalten ist, dass Daten sind an einen anderen Benutzer gesendet werden, der einen Web-Socket vollständig geöffnet hat andere Instanz. Man kann sich leicht ein System vorstellen, in dem eine Nachricht enthalten ist Broker (z. B. Rabbitmq) auf jeder Instanz ausgeführt kann eine Nachricht gesendet werden enthält die Daten, die über Web-Sockets an den Client gesendet werden sollen zu dieser Instanz. Aber wie kann der Behandler dieser Nachrichten zugreifen? die Web-Buchse, die in einem Arbeitsprozess von Gunicorn empfangen wurde? Die High-Level-Python-Web-Socket-Objekte erstellt gevent-websocket und einem Arbeiter zur Verfügung gestellt werden kann nicht gebeizt werden (sie sind Instanz Methoden ohne Unterstützung für Beizen), so dass sie nicht leicht geteilt werden können durch einen Arbeitsprozess zu einem lang andauernden externen Prozess.
In der Tat, die Wurzel dieser Frage kommt auf, wie Web-Sockets die von HTTP-Anfragen von Clients initiiert und von WSGI bearbeitet werden Handler in Servern wie Gunicorn werden von extern zugegriffen Prozesse? Es scheint nicht richtig , dass Gunicorn Worker verarbeitet, die HTTP-Anfragen behandeln sollen, würden lange laufen Threads, die an Web-Sockets hängen und die Verarbeitung von Nachrichten von unterstützen andere Prozesse, um Nachrichten an die Web-Sockets zu senden, die es waren durch diese Arbeiterprozesse verbunden.
Kann jemand erklären, wie Web-Sockets und WSGI-basierte HTTP-Anfrage Handler können möglicherweise in der Umgebung interagieren, die ich beschrieben habe?
Danke.
Ich denke, du hast die richtige Einschätzung gemacht, dass mod_wsgi + websockets eine fiese Kombination ist.
Sie würden alle Ihre wsgi-Mitarbeiter von den Web-Sockets gejagt sehen, und ein Versuch, die Größe des Worker-Pools (massiv) zu erhöhen, würde den Server wahrscheinlich wegen der Speicherauslastung und Kontextwechsel ersticken.
Wenn Sie sich an die synchrone wsgi-Worker-Architektur halten möchten (im Gegensatz zum reaktiven Ansatz, der von gevent, twisted, tornado usw. implementiert wird), würde ich vorschlagen, sich in uWSGI als Anwendungsserver zu betrachten. Neuere Versionen können auf die alte Weise mit einigen URLs umgehen (d. H. Ihre vorhandenen Django-Ansichten funktionieren immer noch genauso wie zuvor) und leiten andere URLs an einen asynchronen Websocket-Handler weiter. Dies könnte ein relativ reibungsloser Migrationspfad für Sie sein.
Es scheint nicht richtig zu sein, dass Gunicorn-Worker-Prozesse, die HTTP-Anfragen bearbeiten sollen, lang laufende Threads erzeugen, die an Web-Sockets hängen und die Verarbeitung von Nachrichten anderer Prozesse unterstützen, um Nachrichten an die angehängten Web-Sockets zu senden durch diese Arbeiterprozesse.
Warum nicht? Dies ist schließlich eine langwierige Verbindung. Ein lang andauernder Thread, der sich um eine solche Verbindung kümmert, erscheint mir ... absolut natürlich.
In solchen Fällen wird das Schreiben oft getrennt vom Lesen behandelt.
Ein Arbeiter, der gerade eine Websocket-Verbindung bearbeitet, würde auf die Nachricht warten, die von einem Nachrichtenserver herunterkommt, und dann den Websocket weiterleiten.
Sie können auch die async-freundlichen Warteschlangen von gevent verwenden, um die Nachrichtenübergabe in Code zu verarbeiten, wenn Sie möchten.