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.
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 .
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.
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"
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:
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.
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