gunicorn – Sam & Max http://sametmax.com Du code, du cul Wed, 30 Oct 2019 15:34:04 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.7 32490438 L’erreur “broken pipe” avec les serveurs Python tel Gunicorn http://sametmax.com/lerreur-broken-pipe-avec-les-serveurs-python-tel-gunicorn/ Fri, 26 Apr 2013 06:46:15 +0000 http://sametmax.com/?p=5885 Quand on commence à avoir pas mal de trafic sur son site, on commence à noter l’apparition d’une erreur inquiétante :

Traceback (most recent call last):
File "gunicorn/workers/async.py", line 44, in handle
self.handle_request(req, client, addr)
File "gunicorn/workers/ggevent.py", line 88, in handle_request
super(GeventWorker, self).handle_request(*args)
File "gunicorn/workers/async.py", line 83, in handle_request
resp.write(item)
File "gunicorn/http/wsgi.py", line 275, in write
util.write(self.sock, arg, self.chunked)
File "gunicorn/util.py", line 232, in write
sock.sendall(data)
File "gevent/socket.py", line 480, in sendall
data_sent += self.send(_get_memory(data, data_sent), flags)
File "gevent/socket.py", line 451, in send
return sock.send(data, flags)
error: [Errno 32] Broken pipe

Et plus il y a de trafic, plus cette erreur apparait dans les logs.

Pourtant, impossible de trouver la cause de l’erreur, tout semble bien marcher, le serveur pète la forme et ipdb ne donne rien du tout.

La raison pour laquelle vous ne trouvez rien, c’est qu’il n’y a rien à trouver. Cette erreur est levée par le module socket quand il essaye d’écrire sur une connexion qui s’est fermée brutalement.

Or le serveur ne peut pas savoir quand une connexion s’est fermée si le client ne lui envoie pas le message. Et il peut y avoir énormément de raisons pour que ça arrive : fermeture d’un onglet en plein chargement, crash du navigateur, extinction du PC pendant la réponse, etc.

Vous en voyez plus quand le trafic augmente tout simplement parce que statistiquement, avec plus de visiteurs, ces situations rares se rencontrent plus facilement dans la masse de connexions.

Donc pour l’erreur “broken pipe”, il n’y a rien à faire, à part de monter le log level de votre serveur d’un cran pour qu’il n’affiche plus ça dans vos logs.

]]>
5885
Nginx en reverse proxy + Gunicorn pour vos apps Django http://sametmax.com/nginx-en-reverse-proxy-gunicorn-pour-vos-apps-django/ http://sametmax.com/nginx-en-reverse-proxy-gunicorn-pour-vos-apps-django/#comments Mon, 03 Dec 2012 19:48:22 +0000 http://sametmax.com/?p=3431 Nginx est bien connu depuis quelques années. Puissant serveur HTTP, il peut être utilisé en tant que reverse proxy (mandataire inverse en Français) afin d’améliorer les performances.
Je vous copie/colle les avantages depuis Wikipédia parce que je suis une feignasse:

cache : le mandataire inverse ou (reverse proxy) peut décharger les serveurs Web de la charge de pages/objets statiques (pages HTML, images) par la gestion d’un cache local. La charge des serveurs Web est ainsi généralement diminuée, on parle alors d’« accélérateur web » ou d’« accélérateur HTTP ».
Intermédiaire de sécurité : le mandataire inverse protège un serveur Web des attaques provenant de l’extérieur. En effet, la couche supplémentaire apportée par les mandataires inverses peut apporter une sécurité supplémentaire. La ré-écriture programmable des URL permet de masquer et de contrôler, par exemple, l’architecture d’un site web interne. Mais cette architecture permet surtout le filtrage en un point unique des accès aux ressources Web.
Chiffrement SSL : le mandataire inverse peut être utilisé en tant que « terminateur SSL », par exemple par le biais de matériel dédié,
Répartition de charge : le mandataire inverse peut distribuer la charge d’un site unique sur plusieurs serveurs Web applicatifs. Selon sa configuration, un travail de ré-écriture d’URL sera donc nécessaire,
Compression : le mandataire inverse peut optimiser la compression du contenu des sites.

Pour résumé:

Visiteur > Web > Votre Serveur > Nginx > Gunicorn > Django

Dans la configuration suivante Nginx va servir les fichiers statiques (images, js, etc) et envoyer le reste des requêtes sur Gunicorn. Gunicorn est une interface WSGI entre le serveur HTTP (nginx) et Python, je n’ai pas trouvé de bonne explication sur WSGI à part le site officiel fait par des autistes.

Soit la configuration de Gunicorn suivante (on peut le lancer avec supervisor):

gunicorn_django  myapp.py --bind 127.0.0.1:8080 --log-file /var/log/myapp.gunicorn.log --log-level info --workers 2 --pid /tmp/myapp.pid  --worker-class gevent

Gunicorn va “écouter” en local sur le port 8080, il va logger des infos dans le fichier /var/log/myapp.gunicorn.log (pratique pour le debug si besoin).
Pour les workers et worker-class regardez la doc.

Configurer Nginx:
Dans la conf Nginx on va avoir.

server {
        listen       80;
        server_name mysite.com www.mysite.com;

        location /static/ {
            root  /home/myapp/prod;
            gzip  on;
        }

        location / {
            proxy_pass http://127.0.0.1:8080; # Pass to Gunicorn
            proxy_set_header X-Real-IP $remote_addr; # get real Client IP
        }
}

location va indiquer à Nginx ce qu’il faut faire lorsqu’il rencontre certaines URL.

Dans notre cas le location /static/ va dire à Nginx de servir directement tous les fichiers du répertoire /home/myapp/prod/static pour les URL http://mysite.com/static/… En général les images, javascript, etc.

Pour le reste location / va renvoyer les requêtes sur votre serveur Gunicorn qui va les traiter.

proxy_set_header sert à passer à Gunicorn certaines infos comme l’IP réelle du client (sinon Gunicorn verrait celle de NGinx 127.0.0.1).

De cette manière on ne surcharge pas Gunicorn pour servir nos fichiers statiques, on ajoute une protection (Nginx).
On peut éventuellement mettre en cache certaines pages mais je n’ai jamais utilisé cette option.
Nginx peut également distribuer la charge sur plusieurs serveurs et se charger de la compression des pages (gzip).

]]>
http://sametmax.com/nginx-en-reverse-proxy-gunicorn-pour-vos-apps-django/feed/ 5 3431