web-dev-qa-db-de.com

gunicorn + Nginx: Server über Socket oder Proxy?

Ich habe zwei Strategien für das Hosten einer Django-Anwendung mit Gunicorn und Nginx gesehen.

Eine Strategie besteht darin, Gunicorn auf einem Netzwerkport auszuführen. Zum Beispiel (von http://goodcode.io/blog/Django-nginx-gunicorn/ ):

location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_Host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 10;
    proxy_read_timeout 10;
    proxy_pass http://localhost:8000/;
}

Eine andere Strategie besteht darin, Gunicorn beim Start an einen UNIX-Socket zu binden (z. B. http://michal.karzynski.pl/blog/2013/06/09/Django-nginx-gunicorn-virtualenv-supervisor/ ).

upstream hello_app_server {
    server unix:/tmp/gunicorn.sock fail_timeout=0;
}

...

location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_Host;
    proxy_redirect off;
    if (!-f $request_filename) {
        proxy_pass http://hello_app_server;
        break;
    }
}

Gedanken zu welcher Strategie sind überlegen? Irgendwelche Kommentare zur richtigen Vorgehensweise? Ich neige zum Socket-Ansatz, weil der Overhead, den ich mir vorstelle, durch TCP eingeführt wird. Ich bin am meisten besorgt über die Unterschiede in Bezug auf Header, Verbindungs-Timeouts und dergleichen zwischen den Implementierungsbeispielen, die ich gesehen habe.

24
masonjarre

Neben dem geringen TCP/IP-Overhead gibt es keinen großen Unterschied. Jeder listen () - Socket erhält eine Verbindungswarteschlange, und Accept () öffnet eine Verbindung aus dieser Warteschlange. In gunicorn knipst jeder Worker nur eine neue Verbindung aus dieser Warteschlange, damit er sich nicht ändern kann. Der Unterschied ist die Leistung (Sockets sind etwas schneller) und die Portabilität (Port: IP ist flexibler). Unix-Domänensockets bieten eine etwas bessere Leistung, während ein Socket, der mit localhost verbunden ist, eine etwas bessere Portabilität bietet, wenn Sie die Server-App in ein anderes Betriebssystem verschieben. Sie können dies einfach tun, indem Sie die IP-Adresse von localhost in einen anderen Hostnamen ändern .

24
radtek

Socket-Verkehr ist eine einfache Wahl, wenn sowohl Ihr Webserver als auch Ihr App-Server (wsgi) auf demselben Computer vorhanden sind. Sie benötigen jedoch Netzwerkanschlüsse über Netzwerkverbindungen, da Sockets nicht über das Netzwerk funktionieren können.

  1. Wenn Webserver und Appserver auf demselben Computer liegen, dann GO SOCKET
  2. Wenn sich Webserver und Appserver im Netzwerk befinden - GO PORTS
13
Kashif Siddiqui

würde Socket-Verkehr über TCP/IP bevorzugen, da kein zusätzlicher Port erforderlich ist, um geöffnet zu werden. Je weniger Ports geöffnet werden, desto fester wird Ihr System 

wie hier vorgeschlagen "seien Sie paranoid" https://hynek.me/talks/python-deployments/

"UNIX-Dateisockets mit eingeschränkten Berechtigungen sind Ihre Freunde. Und Sie können aufhören, Portnummern zu erhalten"

4
infinityLoop

Hier sind die Ergebnisse meines Tests TCP Proxy über Unix-Socket:

Setup: Nginx + gunicorn + Django läuft auf 4 m4. Großen Knoten auf AWS.

Eine Million Anfragen werden in einem Fenster von etwa 30 Minuten gestellt:

 4 m4.xlarge ninstances running TCP PRoxy vs. Unix socket

eine Instanz ist bei 100% und 3 andere sind alle zu 70% CPU.

TCP vs. Socket ist praktisch identisch Zeitpunkt für das Durchführen von 1000000 Anforderungen 

ist 27 Minuten für TCP Proxy

und 31 Minuten für die Unix-Buchse.

In diesem speziellen Setup kein Leistungsvorteil für Unix-Sockets. 

2
dovka

Ich weiß, dass ich zu spät zu dieser Party komme. Wenn das so ist, kann dies von Nutzen sein, wenn Sie versuchen, dies mit Red Hat Linux unter SELinux zu erreichen.

Wenn Sie versuchen, Steckdosen zu verwenden, kommt es zu Problemen. Ich gab auf.

Es steht auch im Weg, wenn Sie versuchen, Gunicorn über einen beliebigen TCP Port zu binden. Standardmäßig (auf Centos 1708) gibt es eine Teilmenge von Ports, die SELinux gerne verwendet: 80,81,443,488,8008,8009,8443,9000

Ich bin mit 8009 gegangen, aber anscheinend für einen anderen Port, den man benutzen kann

semanage -a -t http_port_t -p tcp $PORTNUMBER

und um die Liste der Ports anzuzeigen

semanage port -l

0
nigel222