web-dev-qa-db-fra.com

gunicorn + nginx: serveur via socket ou proxy?

J'ai vu deux stratégies pour héberger une application Django avec gunicorn et nginx.

Une stratégie consiste à exécuter gunicorn sur un port réseau. Par exemple (from 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/;
}

Une autre stratégie consiste à lier gunicorn à un socket UNIX au démarrage (par exemple, 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;
    }
}

Réflexions sur quelle stratégie est supérieure? Des commentaires sur la bonne façon de faire chacun? Je me penche en faveur de l'approche par sockets à cause des frais généraux que j'imagine est introduit par TCP. Je suis surtout préoccupé par les différences entre les en-têtes, les délais de connexion et autres exemples d'implémentation que j'ai vus.

24
masonjarre

Outre la petite surcharge TCP/IP, il n'y a pas beaucoup de différence. Chaque socket listen () obtient une file d'attente de connexion et accept () ouvre simplement une connexion à partir de cette file d'attente. Dans gunicorn, chaque travailleur crée simplement une nouvelle connexion de cette file d'attente afin qu'il ne puisse pas en changer. La différence réside dans les performances (les sockets étant un peu plus rapides) et la portabilité (port: IP est plus flexible). Les sockets de domaine Unix vous donneront de meilleures performances, alors qu'une socket connectée à localhost vous donnera une meilleure portabilité si vous déplacez l'application serveur vers un autre système d'exploitation, vous pouvez le faire en changeant simplement l'adresse IP de localhost vers un autre nom d'hôte. .

24
radtek

Le trafic de socket sera un choix facile si votre serveur Web et votre serveur d'applications (wsgi) existent sur le même ordinateur. Cependant, vous aurez besoin de ports réseau sur les connexions réseau car les sockets ne peuvent pas fonctionner sur le réseau.

  1. Si le serveur Web et le serveur d'applications se trouvent sur le même ordinateur - GO SOCKET
  2. Si le serveur Web et le serveur d'applications sont sur le réseau - GO PORTS
13
Kashif Siddiqui

préférerait le trafic de socket à TCP/IP car aucun port supplémentaire n'est nécessaire pour être ouvert. moins il y a de ports ouverts, plus votre système est durci 

comme suggéré ici "être paranoïaque" https://hynek.me/talks/python-deployments/

"Les sockets de fichiers UNIX avec des autorisations restrictives sont vos amis. Et vous pouvez arrêter de fournir des numéros de ports"

4
infinityLoop

Voici les résultats de mon test TCP Proxy via socket Unix:

Configuration: Nginx + gunicorn + Django s'exécutant sur 4 noeuds m4.xlarge sur AWS.

1 million de demandes sont effectuées sur une fenêtre d'environ 30 minutes:

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

une instance est à 100% et 3 autres sont tous à 70% de CPU.

TCP vs le socket est pratiquement identique Le moment pour faire des requêtes de 1000000 

est de 27 minutes pour le proxy TCP

et 31 minutes pour le socket Unix.

Dans cette configuration particulière, aucun avantage en termes de performances de socket unix. 

2
dovka

Je sais que je suis en retard pour cette fête, mais cela peut être utile si vous essayez de faire en sorte que cela fonctionne avec la version Linux de Red Hat avec l'application de SELinux.

Cela vous gêne si vous essayez d'utiliser des sockets. J'ai abandonné.

Cela vous gênera également si vous essayez de lier Gunicorn via un port TCP arbitraire. Par défaut (sur Centos 1708), il existe un sous-ensemble de ports que SELinux est heureux d’utiliser: 80,81,443,488,8008,8009,8443,9000

Je suis allé avec 8009 mais apparemment pour un autre port que vous pouvez utiliser

semanage -a -t http_port_t -p tcp $PORTNUMBER

et voir la liste des ports

semanage port -l

0
nigel222