Maison >développement back-end >Tutoriel Python >Comment utiliser Nginx + UWSGI

Comment utiliser Nginx + UWSGI

巴扎黑
巴扎黑original
2017-04-05 14:56:181489parcourir

Après de nombreuses expérimentations (sur disqus.com et getsentry.com), je peux définitivement dire : uwsgi devrait devenir le standard dans le monde Python. Combinez-le avec nginx et vous obtiendrez une meilleure expérience de performances sur les threads (ou non-threads) sur les applications Web basées sur Python.

Mise à jour : ignorez le vieux dicton "toute métrique que vous donnez est lente", par requêtes, je veux dire ici les nœuds backend, ils gèrent les événements entrants (requêtes allant de 20 Ko à 1 Mo), sautant à travers différents sauts dans le réseau Autorisation et quota politiques, et la plupart forment des opérations de file d’attente. Déchargez-vous autant de charge de travail que possible. (Il y a un problème avec la traduction de ce paragraphe, merci de vous référer au texte original, ndlr du traducteur)

Stratégie de services

Il existe déjà plusieurs façons d'exécuter des applications Python. Je ne vais pas utiliser mod_wsgi, et surtout, je n'essaie pas d'expliquer comment fonctionne le modèle d'événement. Je ne pense pas qu'ils soient encore utilisés dans le monde Python, donc le sujet de cet article ne concerne pas les applications Python traditionnelles threadées (ou multi-processus).

Au lieu de cela, je me concentrerai sur les deux solutions les plus populaires que je connais le mieux : gunicorn et uwsgi.

Gunicorn (serveur wsgi pour plateforme Python UNIX)

En regardant le passé, la solution pour le serveur Web de Python était essentiellement mod_wsgi. L’une des méthodes les plus populaires (ou considérées comme à la mode) récemment est le Gunicorn.

En fait, je recommande quand même d'utiliser gunicorn, ce qui réduit considérablement les désagréments : il intègre magnifiquement Django et est facile à mettre en place.

Il possède également 10 % des mêmes options de configuration que uwsgi (ce qui est une bonne chose pour certaines personnes), mais à part cela, en comparaison, il offre presque les mêmes fonctionnalités de base que uwsgi (ou tout autre serveur Web Python).

uwsgi

À mon avis, c'est la seule option, de Gunicorn à uwsgi. Il y aura des performances plus élevées, plus d'options de configuration faciles à comprendre et la possibilité d'interagir avec nginx via le protocole ajoute également des avantages.
Sa configuration est également assez simple, il suffit de trouver un article qui y est lié, nous y reviendrons plus tard.
J'ai commencé à utiliser uwsgi pour exécuter certaines applications, et j'ai utilisé –processes=10 et –threads=10 pour tester le multi-CPU du serveur. Il y avait deux objectifs :

  • . Soutien


  • Testez la possibilité de réduire l'utilisation de la mémoire


  • Tester la prise en charge de la sécurité des fils

(Quant à savoir si ces tests en valent la peine, DISQUS s'exécute dans un seul thread. Je souhaite le garder aussi simple que possible et maximiser les capacités de chaque nœud)

Itération continue vers le succès

Nous avons réduit le temps de réponse moyen de l'API à moins de 40 ms, ce dont je suis très fier. Le temps de réponse de l'API dont je parle ici fait référence au temps qu'il faut entre la requête arrivant sur le serveur Python et le moment où le serveur renvoie la réponse au proxy.

Malheureusement, lorsque nous avons commencé à recevoir de plus en plus de trafic et à connaître des pics d'accès, les temps de réponse ont commencé à se détériorer. Les temps de réponse fluctuants ne correspondaient plus à nos attentes initiales, même si nous avions encore environ 30 % de la mémoire sur le nœud de service et 60 %. % des ressources sont disponibles.

Après de nombreux ajustements, nous avons désactivé un grand nombre de processus uwsgi et laissé nginx les équilibrer (auparavant, nous laissions uwsgi lui-même équilibrer la charge).

Cela signifie qu'au lieu de faire uwsgiprocess=10, nous exécutons 10 instances uwsgi distinctes au lieu de --processes=10.

Le résultat est un temps de réponse moyen magnifique et cohérent de 20 ms.

Temps de réponse de l'API

Assemblez-les

J'aime faire les choses plutôt que d'en parler, alors je vais vous donner ici une configuration réelle de nos serveurs en ligne.

nginx

Le premier élément de configuration est Nginx. Nous devons réellement calculer et ajouter le nombre de backends de processus uwsgi, donc les choses sont un peu compliquées.

​Nous créons d'abord une liste de configuration sur notre page web :

# recipes/web.rb

hosts = (0..(node[:getsentry][:web][:processes] - 1)).to_a.map do |x|
  port = 9000 + x
  "127.0.0.1:#{port}"
end

template "#{node['nginx']['dir']}/sites-available/getsentry.com" do
  source "nginx/getsentry.erb"
  owner "root"
  group "root"
  variables(
    :hosts => hosts
  )
  mode 0644
  notifies :reload, "service[nginx]"
end

La configuration de Nginx est très simple :

# templates/getsentry.erb

upstream internal {
<% @hosts.each do |host| %>
  server <%= host %>;
<% end %>
}

server {
  location / {
    uwsgi_pass         internal;

    uwsgi_param   Host                 $host;
    uwsgi_param   X-Real-IP            $remote_addr;
    uwsgi_param   X-Forwarded-For      $proxy_add_x_forwarded_for;
    uwsgi_param   X-Forwarded-Proto    $http_x_forwarded_proto;

    include uwsgi_params;
  }
}

Nous avons maintenant défini le nombre d'hôtes uwsgi et attribué des valeurs de poids, en commençant par le port 9000, qui sont les adresses de socket utilisées par la configuration uwsgi.

uwsgi

D'un autre côté, nous utilisons superviseur pour contrôler le processus uwsg, qui est également très simple :

# recipes/web.rb

command = "/srv/www/getsentry.com/env/bin/uwsgi -s 127.0.0.1:90%(process_num)02d --need-app --disable-logging --wsgi-file getsentry/wsgi.py --processes 1 --threads #{node[&#39;getsentry&#39;][&#39;web&#39;][&#39;threads&#39;]}"

supervisor_service "web" do
  directory "/srv/www/getsentry.com/current/"
  command command
  user "dcramer"
  stdout_logfile "syslog"
  stderr_logfile "syslog"
  startsecs 10
  stopsignal "QUIT"
  stopasgroup true
  killasgroup true
  process_name &#39;%(program_name)s %(process_num)02d&#39;
  numprocs node[&#39;getsentry&#39;][&#39;web&#39;][&#39;processes&#39;]
end

Sélection du lieu

À moins que quelqu'un ne propose un argument très convaincant pour expliquer pourquoi il devrait y avoir un autre moyen (ou quelque chose qui ne fonctionne pas dans ce cas), j'aimerais entendre parler de ce modèle à mesure que le monde Python devient plus standard. À tout le moins, j'aimerais voir l'étincelle d'un débat sur la manière d'améliorer la gestion des processus au sein de uwsgi.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn