<< précédentsuivant >>

Chapitre 20: Déployer Django

Tout au long de ce livre, nos avons mentionné les divers objectifs qui dirigent le développement de Django. Facilité d’utilisation, facilité d’accès aux nouveaux programmeurs, abstraction des tâches répétitives - tous cela motivant les développeurs Django.

Cependant, depuis la création de Django, il y a toujours eu un autre objectif important: Django doit être facile à déployer, et doit permettre les plus grandes quantités de trafic possible avec des ressources limitées.

Ces motivations sont apparente lorsque vous observez l’historique de Django: un petit journal familial du Kansas peut difficilement se permettre le haut de gamme en matière de serveur, les développeurs de Django étaient donc sensibles dès l’origine à tirer les meilleures performances de ressources limitées. En effet, pendant des années, les développeurs de Django ont du assumer les fonctions d’administrateurs de leur propre système - il n’y avait tout simplement pas assez de matériel justifiant un administrateur dédié - alors même que leurs sites traitaient des dizaines de millions de connexions par jour.

Lorsque Django est devenu un projet open source, cette attention à la performance et à la facilité de déploiement devint importante pour une autre raison: les développeurs amateurs ont les mêmes besoins. Les individus qui veulent utiliser Django sont heureux d’apprendre qu’ils peuvent héberger des sites au trafic plus ou moins important pour moins de 10€ par mois.

Mais s’adapter par le bas n’est que la moitié du problème. Django a aussi besoin de s’adapter par le haut pour répondre aux besoins des grandes organisations et des grandes entreprises. Ici, Django adopte la philosophie courament répandue dans la pile Web basée sur les solutions LAMP et usuellement appelée shared nothing (ne rien partager).

Qu’est-ce que LAMP ?

L’acronyme LAMP décrivait à l’origine l’utilisation d’un jeu d’applications open source populaires utilisé pour motoriser beaucoup de site web:

  • Linux (système d’exploitation)
  • Apache (serveur web)
  • MySQL (système de gestion de base de données)
  • PHP (langage de programmation)

Au fils du temps cependant, l’acronyme à été utiliser pour faire référence à la philosophie de cette pile d’applications open source plutôt qu’à tout autre pile logicielle. Ainsi, même si Django utilise Python et n’est pas associé à une base de données particulières, la philosophie éprouvée de la pile LAMP a permis la mentalité de développement de Django.

Il y a eu quelques tentatives (la plupart humoristiques) de mette en place un acronyme similaire pour décrire la pile technologique de Django. Les auteurs de ce livre sont fans de LAPD (Linux, Apache, PostgreSQL, et Django) ou PAID (PostgreSQL, Apache, Internet, et Django). Utilisez Django et soyez PAID ! (ndt: jeu de mot, get paid signifiant «être payé»).

« Ne rien partager »

À la base, la philosophie de « ne rien partager » (share-nothing) est simplement l’application du faible couplage à l’intégralité de la pile logicielle. Cette architecture se place comme la réponse directe à ce qu’était à l’époque l’architecture dominante: un serveur d’application internet monolithique qui englobait le langage, la base de données, et le serveur internet - et parfois même des parties du système d’exploitation - en un seul processus (par exemple, Java).

Lorsqu’il s’agit de l’adapter, ceci peut devenir un problème majeur; il est pratiquement impossible de séparer le travail d’un processus monolithique sur différentes machines physiques, c’est pourquoi ces applications monolithiques nécessitent des serveurs extrêmement puissants. Ces serveurs, bien sûr, coûtent des dizaines voir même des centaines de milliers d’euros, plaçant les sites internet de grande envergure hors de portée des particuliers et des petites entreprises.

Toutefois, la communauté LAMP à remarqué que si vous dissociez chaque pièce de la pile

logicielle en composants individuels, vous pouviez facilement démarrer avec un serveur bon marché et ajouter simplement d’autres serveurs bon marché en fonction de la croissance. Si votre serveur de base de données à 3 000€ ne supporte pas la charge, vous en achetez simplement un second (ou un troisième, un quatrième) jusqu’à ce que cela fonctionne. Si vous avez besoin de plus de capacité de stockage, vous ajoutez un serveur NFS.

Pour que ceci fonctionne, cependant, les applications web ne doivent plus considérer que le même serveur gérera chaque requête - ou même chaque partie d’une unique requête. Dans le déploiement LAMP (et Django) à grande échelle, près d’une demi-douzaine de serveur peuvent êtres impliqué dans la prise en charge d’une seule page ! Les répercussions de ceci sont nombreuses, mais se résument à ces points:

  • L’état ne peut être conservé localement. En d’autre termes, toute donnée qui doit être disponible pour de multiples requêtes doit être stockée dans une sorte de stockage persistant tel qu’une base de données ou un cache centralisé.
  • Le logiciel ne peut considérer que les ressources sont locales. Par exemple, la plate-forme web ne peut considérer que la base de données tourne sur le même serveur; ellle doit être capable de se connecter sur un serveur de base de données distant.
  • Chaque composant de la pile doit être facilement déplacé ou répliqué. Si Apache, pour une raison quelqconque, ne fonctionne pas lors d’un déploiement donné, vous devez être capable de le substituer par un autre serveur en un minimum de soucis. Ou, au niveau matériel, si un serveur web tombe, vous devez pouvoir le remplacer physiquement par une autre boîte en un minimum de temps. Souvenez-vous, toute cette philosophie est basée autour du déploiement sur du matériel courant et bon marché. La défaillance d’une machine individuelle est attendue.

Comme vous devez porbablement vous y attendre, Django gère ceci de manière plus ou moins transparente - aucune partie de Django ne viole ces principes - mais connaître la philosophie aide lorsque vient le temps de monter en charge.

Comment cela fonctionne-t-il ?

Cette philosophie peut être bonne sur le papier (ou sur votre écran), mais fonctionne t-elle vraiment ?

Et bien, au lieu de répondre directement, regardons plutôt une liste non exhaustive des quelques entreprises qui ont basé leur activité sur cette architecture. Quelques noms peuvent vous sembler familier:

  • Amazon
  • Blogger
  • Craigslist
  • Facebook
  • Google
  • LiveJournal
  • Slashdot
  • Wikipedia
  • Yahoo
  • YouTube

Pour paraphraser la fameuse scène de Quand Harry rencontre Sally: « Nous aurons ce qu’ils ont ! »

Note sur les préférences personnelles

Avant d’entrer dans les détails, voici une courte remarque.

L’open source est célèbre pour ce que l’on appelle ses guerres de religions; beaucoup d’encre (numérique) à coulé au sujet des éditeurs de texte (emacs contre vi), les systèmes d’exploitation (Linux contre Windows contre Mac OS), les moteurs de base de données (MySQL contre PostgreSQL), et, «bien sûr», les langages de programmation.

Nous essayons de rester à l’écart de ces batailles. Il n’y à tout simplement pas asser de temps.

Cependant, il y a de nombreux choix à faire lorsqu’il s’agit de déployer Django, et l’on nous demande constament nos préférences. Puisque indiquer ces préférences reviens dangeureusement à tirer une salve dans l’une des batailles mentionnées plus avant, nous nous sommes le plus souvent abstenu. Cependant, par soucis d’hexaustivité et afin de tout révéler, nous les indiquons ici. Nous préférons utiliser:

  • Linux (Ubuntu, plus spécialement) pour le système d’exploitation
  • Apache et mod_python pour le serveur web
  • PostgreSQL pour le serveur de base de données

Bien sûr, nous pouvons présenter beaucoup d’utilisateurs de Django qui ont fait d’autres choix avec succès.

Utiliser Django avec apache et mod_python

Apache et mod_python sont actuellement la configuration la plus solide pour utiliser Django sur un serveur de production.

mod_python (http://www.djangoproject.com/r/mod_python/) est un plug-in Apache qui embarque Python au sein d’Apache et charge le code Python en mémoire lorsque le serveur démarre. Le code reste en mémoire tout au long de la vie d’une processus Apache, ce qui amène à des gains de performances significatifs par rapport à d’autre configurations de serveur.

Django nécessite Apache 2.x et mod_python 3.x, et nous préferons le MPM prefork d’Apache, par opposition au MPM worker.

Note

Configurer Apache est largement en dehors de l’objectif de ce livre, nous ne mentionnerons donc les détails qu’en fonction des besoins. Heureusement, de nombreuses ressources de qualité sont disponibles si vous devez en savoir plus au sujet d’Apache. En voici quelques unes parmis celles que nous apprécions:

Configuration de base

Pour configurer Django avec mod_python, assurez d’abord qu’Apache soit installé et que le module mod_python soit activé. Cela signifie habituellement que la directive LoadModule est présente dans votre fichier de configuration d’Apache. Il devrait ressembler à ceci:

LoadModule python_module /usr/lib/apache2/modules/mod_python.so

Ensuite, éditez votre fichier de configuration Apache et ajoutez les lignes suivantes:

<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonDebug On
</Location>

Assurez vous de remplacer mysite.settings avec le DJANGO_SETTINGS_MODULE approprié à votre site.

Ceci indique à Apache qu’il lui faut «utiliser mod_python pour tout URL à la racine “/” et en dessous, grâce au gestionnaire mod_python». La valeur de DJANGO_SETTINGS_MODULE est transmise de façon à ce que mod_python sache quel est le paramètre à utiliser.

Notez que nous utilisons la directive <Location>, et non pas <Directory>. Cette dernière est utilisée pour pointer les emplacements de votre système de fichier, alors que <Location> pointe les emplacements dans la structure de l’URL d’un site web. <Directory> n’aurait pas de sens ici.

Apache tourne probablement sous un utilisateur différent que celui sous lequel vous êtes connecté et peut présenter des chemins systèmes différents. Vous aurez peut être à indiquer à mod_python comment trouver votre projet et où trouver Django.

PythonPath "['/path/to/project', '/path/to/django'] + sys.path"

Vous pouvez aussi ajouter des directives telles que PythonAutoReload Off pour des raisons de performance. Consultez la documentation sur mod_python pour une liste complète des options.

Notez que vous devez placer PythonDebug Off sur un serveur de production. Si vous laissez PythonDebug On, vos utilisateurs verrons les rapports d’erreur de Python (pas très jolis et révélateurs) si quelque chose se passe mal avec mod_python.

Redémarrez Apache, et toute requête vers votre site (ou votre hôte virtuel si vous avez placez cette directive dans un bloc <VirtualHost>) sera servi par Django.

Note

Si vous déployez Django dans un sous répertoire - c’est à dire au delà de «/» - Django ne modifiera pas le prefix d’URL dans votre modèle d’URL. Si votre configuration d’Apache ressemble à ceci:

<Location "/mysite/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonDebug On
</Location>

alors tous vos patron d’URL doivent commencer par "/mysite/". Pour cette raison nous recommendons habituellement de déployer Django à la pracine de votre domaine ou de votre hôte virtuel. Alternativement, il vous suffit de déplacer votre configuration d’URL d’un niveau en utilisant ce type d’URLconf:

urlpatterns = patterns('',
    (r'^mysite/', include('normal.root.urls')),
)

Faire tourner de multiples installations Django avec la même instance d’Apache

Il est tout à fait possible de faire tourner de multiples installations de Django sur la même instance Apache. Vous pourriez vouloir faire ceci si vous êtes un développeur web indépendant avec de multiples clients mais un unique serveur.

Pour faire cela, utilisez simplement VirtualHost comme ceci:

NameVirtualHost *

<VirtualHost *>
    ServerName www.example.com
    # ...
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</VirtualHost>

<VirtualHost *>
    ServerName www2.example.com
    # ...
    SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
</VirtualHost>

Si vous devez placer deux installations Django dans le même VirtualHost, vous devrez prendre des précautions particulières pour vous assurez que le code du cache mod_python ne bouscule pas les choses. Utilisez la directive PythonInterpreter pour donner aux diverses directives <Location> des interpreteurs séparé:

<VirtualHost *>
    ServerName www.example.com
    # ...
    <Location "/something">
        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
        PythonInterpreter mysite
    </Location>

    <Location "/otherthing">
        SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
        PythonInterpreter mysite_other
    </Location>
</VirtualHost>

Les valeurs de PythonInterpreter n’importe par réellement, dès lors qu’elles sont différentes sur les deux blocs Location.

Lancer un serveur de développement avec mod_python

Parce que les caches mod_python charges du code Python, lorsque vuos déployez des sites Django avec mod_python vous devrez redémarrer Apache à chaque fois que vous apportez des modifications à votre code. Ceci pouvant être laborieux, voici une petite astuce pour éviter cela; ajoutez simplement MaxRequestsPerChild 1 à votre fichier de configuration pour obliger Apache à tout recharger à chaque requête. Ne faîtes pas cela sur un serveur de production, ou nous vous retirerons vos privilèges Django.

Si vous êtes le genre de programmeur qui débug en utilisant des instructions print de-ci de-là (nous en sommes), notez que les instructions print n’ont pas d’effet avec mod_python; elles n’apparaissent dans les logs d’Apache, comme vous pourriez l’attendre. Si vous avez besoin d’afficher des informations de débugage dans une configuration utilisant mod_python, vous utiliserez probablement le module de connection Python standard. Plus d’informations sont disponibles à l’adresse http://docs.python.org/lib/module-logging.html. Alternativement, vous pouvez ajouter les informations de débugage au gabarit de votre page.

Servir des fichiers médias depuis une instance Apache

Django ne doit pas être utilisé pour fournir directement des fichiers médias; laissez ce travail à n’importe quel serveur que vous choisirez. Nous vous recommandons d’utiliser un serveur web séparé (c’est à dire, un serveur où Django ne tourne pas déjà) pour fournir des médias. Pour plus d’informations, lisez la section «Monter en charge».

Si, toutefois, vous n’avez pas d’autre options que de servir des fichiers médias depuis le même VirtualHost Apache que Django, voici comment vous pouvez désactiver mod_python pour une région particulière du site:

<Location "/media/">
    SetHandler None
</Location>

En ajustant Location à l’URL racine de vos fichiers média.

Vous pouvez aussi utiliser <LocationMatch> pour la correspondance avec une expression régulière. Par exemple, ceci place Django à la racine du site mais désactive explicitement Django pour le sous répertoire media et pour toutes les URLs se terminant par .jpg, .gif, ou .png:

<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>

<Location "/media/">
    SetHandler None
</Location>

<LocationMatch "\.(jpg|gif|png)$">
    SetHandler None
</LocationMatch>

Pour tous ces cas, vous devrez placer la directive DocumentRoot de façon à ce qu’Apache sache où trouver vos fichiers statiques.

Gestion des erreurs

Lorsque vous utilisez Apache/mod_python, les erreurs seront captées par Django - en d’autres termes, elles ne se propagerons pas au niveau d’Apache et n’apparaitrons pas dans le fichier error_log d’Apache.

L’exception à cela se produit si quelque chose est vraiment incohérent dans votre configuration de Django. Dans ce cas, vous verrez une page «Internal Server Error» dans votre navigateur et l’intégralité du rapport Python dans votre fichier Apache error_log. La trace error_log est répartie sur plusieurs ligne (oui, c’est sale et plutot difficile à lire, mais c’est ainsi que mod_python fait les choses).

Gérer une erreur de segmentation

Parfois, Apache fait une erreur de segmentation lors de l’installation de Django. Lorsque ceci arrive, c’est presque toujours le fait d’une des deux causes, sans liens avec Django lui même:

  • il se peut que votre code Python importe le module pyexpat (utilisé pour parcourir du XML), ce qui peut entrer en conflit avec la version embarquée dans Apache. Pour des informations complètes, lisez «Expat Causing Apache Crash» à l’adresse http://www.djangoproject.com/r/articles/expat-apache-crash/.
  • il est possible que vous fassiez tourner mod_python et _mod_php dans la même instance Apache, avec MySQL pour moteur de base de données. Dans certains cas, ceci génère un problème connu sous mod_python, problème lié à un conflit de version entre le moteur MySQL de PHP et de Python. Des informations complètes se trouvent dans une entrée de la FAQ mod_python, accessible à l’adresse http://www.djangoproject.com/r/articles/php-modpython-faq/.

Si vous continuez à avoir des problèmes lors du paramètrage de mod_python, une bonne chose à faire est de récupérer un site fonctionnant uniquement avec mod_python, sans le framework Django. C’est une façon simple d’isoler les problèmes spécifiques à mod_python. L’article «Getting mod_python Working» détaille cette procédure: http://www.djangoproject.com/r/articles/getting-modpython-working/.

l’étape suivante est l’édition de votre code de test et l’ajout d’un import de tout le code spécifique à Django que vous utilisez - vos vues, vos modèles, vos URLconfs; la configuration de votre RSS, et ainsi de suite. Placez ces imports dans votre gestionnaire de test et testez l’acces aux URL dans un navigateur. Si cela cause un crash, vous avez confirmez qu’il s’agit bien de l’importation de code Django qui pause problème. En réduisant graduellement le jeu d’imports jusqu’à ce que le crash n’est plus lieu, vous trouverez le module spécifique qui cause le problème. explorez alors ces modules et consultez aussi ce qu’ils importent si nécessaire. Pour plus d’aide sur le sujet, des outils comme ldconfig sous Linux, otool sous Mac OS, et ListDLLs (de SysInternals) sous Windows peuvent vous aider à identifier des dépendances partagées et de possibles conflits de versions.

Utiliser Django avec FastCGI

Bien que Django sous Apache et mod_python soit la configuration de déploiement la plus robuste, beaucoup de personnes utilisent l’hebergement mutualisé, où FastCGI est la seule option de déploiement envisageable.

En complément, dans certaines situations, FastCGI permet une meilleure sécurité et potentiellement de meilleures performances que mod_python. Pour de petits sites, fastCGI peut aussi être plus léger qu’Apache.

Tour d’horizon de FastCGI

FastCGI est un moyen efficace de permettre à une application externe de servir des pages à un serveur web. Le serveur Web délègue les requêtes web entrantes (via un socket) à FastCGI, qui exécute le code et transmet la réponse au serveur web, qui à son tout, la renvoie au navigateur web du client.

Tout comme mod_python, FastCGI autorise le code à rester en mémoire, permettant ainsi aux requêtes d’être servi sans délai. À la différence de mod_python, un processus FastCGI ne tourne pas dans un processus du serveur web, mais dans un processus séparé, persistant.

Note

Pourquoi lancer du code sous des processus séparés ?

Traditionnelement, mod_* d’Apache embarque divers langages de scripts (plus particulièrement PHP, Python/mod_python, et Perl/mod_perl) au sein de l’espace processus de votre serveur web. Même si cela diminue le temps de démarrage (puisque le code n’a aps a être lu depuis le disque à chaque requête), c’est au prix de l’utilisation de la mémoire.

Chaque processus Apache récupère une copie du moteur Apache, complétée par toutes les fonctionnalités d’Apache dont Django ne tire tout simplement pas partie. Les processus FasctCGI, d’un autre côté, n’ont que la surchage mémoire liée à Python et Django.

Du fait de la nature de FastCGI, il est aussi possible d’avoir des processus qui tournent sous un compte utilisateur différent du processus appartenant au serveur web. C’est un apport sympathique à la sécurité des systèmes distribués, parce que cela signifie que vous pouvez sécuriser votre code vis à vis des autres utilisateurs.

Avant que vous ne commencier à utiliser FastCGI avec Django, vous devrez installer flup, une bibliothèque Python pour gérer FastCGI; Certains utilisateurs ont rapportés des pages manquantes avec les anciennes versions de flup, vous préférerez probablement utiliser la dernière version SVN. flup est disponible à l’adresse http://www.djangoproject.com/r/flup/.

Lancer votre serveur FastCGI

FastCGI utilise un modèle client/serveur, aussi dans la plupart des cas vous démarrerez le processus FastCGI serveur par vous même. Votre serveur web (qu’il s’agisse d’Apache, lighttpd, ou autre) contacte votre processus Django-FastCGI uniquement lorsque le serveur à besoin de charger une page web dynamique. Puisque le démon est déjà fonctionnel avec le code en mémoire, il est capable de fournir la réponse très rapidement.

Note

Si vous êtes sur un système à l’hébergement mutualisé, vous serez probablement forcé d’utiliser les processus FastCGI gérés côtés serveur. Si vous êtes dans cette situation, vous devriez lire la section intitulée «Utiliser Django avec Apache sur un hébergement mutualisé» qui suit.

Un serveur web peut se connecter à un serveur fastCGI de deux manières: il peut utiliser soit un socket de domaine Unix (un named pipe, littéralement tube nommé, sur les systèmes W32) ou un socket TCP. Ce que vous choisissez est une question de préférences; un socket TCP est habituellement plus simple à cause des soucis de permissions.

Pour démarrer votre serveur, commencer par vous déplacer dans le répertoire de votre projet (où que soit votre manage;py), puis lancez manage.py avec la commande runfcgi:

./manage.py runfcgi [options]

Si vous ajoutez help pour seule option après runfcgi, une liste de toutes les options disponibles s’affichera.

Vous devez préciser s’il s’agit d’un socket ou du couple host et port. Ensuite, lorsque vous aurez paramétré le serveur web, vous n’aurez plus qu’à pointer sur le socket ou sur le host/port que vous avez précisé lors du lancement du serveur FastCGI.

Quelques exemples doivent éclaircir tout cela:

  • lancement d’un serveur threadé sur un port TCP:

    ./manage.py runfcgi method=threaded host=127.0.0.1 port=3033
    
  • lancer un serveur preforké sur un socket de domaine Unix:

    ./manage.py runfcgi method=prefork socket=/home/user/mysite.sock
    pidfile=django.pid
    
  • lancer sans le démoniser (placer à l’arrière plan) le processus (bon pour le débug):

    ./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock
    
Arrêter le démon FastCGI

Si votre processus tourne à l’arrière plan, il est assez facile de l’arrêter: pressez simplement Ctrl+C pour arrêter et quitter le serveur FastCGI. Cependant, lorsque vous aurez affaire aux processus à l’arrière plan, vous devrez recourir à la commande Unix kill.

Si vous précisez l’option pidfile à votre manage.py runfcgi, vous pouvez tuer le démon FastCGI en cours comme ceci:

kill `cat $PIDFILE`

$PIDFILE est le pidfile que vous avez spécifié.

Pour redémarrer facilement votre démon FastCGI sous Unix, vous pouvez utiliser ce petit script shell:

#!/bin/bash

# Replace these three settings.
PROJDIR="/home/user/myproject"
PIDFILE="$PROJDIR/mysite.pid"
SOCKET="$PROJDIR/mysite.sock"

cd $PROJDIR
if [ -f $PIDFILE ]; then
    kill `cat -- $PIDFILE`
    rm -f -- $PIDFILE
fi

exec /usr/bin/env - \
  PYTHONPATH="../python:.." \
  ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE

Utiliser Django avec Apache et FastCGI

Pour utiliser Django avec Apache et FastCGI, vous aurez besoin d’installer et de configurer Apache, avec mod_fastcgi d’installé et de configuré. Consultez la documentation d’Apache et de mod_fastcgi pour les instructions: http://www.djangoproject.com/r/mod_fastcgi/.

Lorsque vous avez complétez le paramètrage, pointez Apache sur votre instance Django FastCGI en éditant le fichier httpd.conf (configuration d’Apache). Vous aurez besoin de faire deux choses:

  • Utilisez la directive FastCGIExternalServer pour préciser l’emplacement de votre server FastCGI.
  • Utilisez mod_rewrite pour pointer les URLs sur le FastCGI approprié.
Préciser l’emplacement du serveur FastCGI

La directive FastCGIExternalServer indique à Apache comment trouver votre serveur FastCGI. Comme l’explique la documentation (http://www.djangoproject.com/r/mod_fastcgi/FastCGIExternalServer/) , vous pouvez préciser s’il s’agit d’un socket ou d’un host. Voici des exemples pour les deux:

# Connect to FastCGI via a socket/named pipe:
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket
/home/user/mysite.sock

# Connect to FastCGI via a TCP host/port:
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host
127.0.0.1:3033

Dans les deux cas, le répertoire /home/user/public_html/ doit exister, même si le fichier /home/user/public_html/mysite.fcgi n’est en fait pas nécessaire. C’est juste un URL utilisé par le serveur web en interne - un point d’entré indiquant quelles requêtes selon l’URL doivent être prise en charge par FastCGI. (Plus sur ce point dans la section suivante).

Utiliser mod_rewrite pour pointer les URLs sur FastCGI

La deuxième étape consiste à dire à Apache qu’il doit utiliser fastCGI pour les URLs qui correspondent à un certain patron. Pour ce faire, utilisez le module mod_rewrite et redirigez les URLs vers mysite.fcgi (ou tout ce que vous précisez dans la directive FastCGIExternalServer, comme expliqué dans le chapitre précédent).

Dans cet exemplen nous indiquons à Apache qu’il faut utiliser FastCGI pour gérer toute requête qui ne représente pas un fichier sur le système de fichier et ne commence pas par /media/. c’est probablement le cas le plus courant, si vous utilisez le site d’admin de Django:

<VirtualHost 12.34.56.78>
  ServerName example.com
  DocumentRoot /home/user/public_html
  Alias /media /home/user/python/django/contrib/admin/media
  RewriteEngine On
  RewriteRule ^/(media.*)$ /$1 [QSA,L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]
</VirtualHost>

FastCGI et lighttpd

lighttpd (http://www.djangoproject.com/r/lighttpd/) est un serveur web léger couramment utilisé pour servir des fichiers statiques. Il supporte le fastCGI nativement et c’est aussi un choix idéal pour servir à la fois des fichiers statiques et des pages dynamiques, si votre site n’a pas de besoins spécifiques à Apache.

Assurez-vous que mod_fastcgi est dans votre liste de modules, quelque part après mod_rewrite et mod_access, mais pas après mod_accesslog. Vous voudrez aussi probablement mod_alias, pour servir les médias d’admin.

Ajoutez ce qui suit à votre fichier de configuration lighttpd:

server.document-root = "/home/user/public_html"
fastcgi.server = (
    "/mysite.fcgi" => (
        "main" => (
            # Use host / port instead of socket for TCP
            fastcgi
            # "host" => "127.0.0.1",
            # "port" => 3033,
            "socket" => "/home/user/mysite.sock",
            "check-local" => "disable",
        )
    ),
)
alias.url = (
    "/media/" => "/home/user/django/contrib/admin/media/",
)

url.rewrite-once = (
    "^(/media.*)$" => "$1",
    "^/favicon\.ico$" => "/media/favicon.ico",
    "^(/.*)$" => "/mysite.fcgi$1",
)
Utiliser de multiples sites Django sur une unique instance lighttpd

lighttpd vous permet d’utiliser la «configuration conditionnelle» afin de pouvoir personnalisé la configuration selon l’hôte. Pour indiquer plusieurs sites FastCGI, ajoutez simplement un bloc conditionnel autour de votre configuration FastCGI et pour chacun des sites:

# If the hostname is 'www.example1.com'...
$HTTP["host"] == "www.example1.com" {
    server.document-root = "/foo/site1"
    fastcgi.server = (
       ...
    )
    ...
}

# If the hostname is 'www.example2.com'...
$HTTP["host"] == "www.example2.com" {
    server.document-root = "/foo/site2"
    fastcgi.server = (
       ...
    )
    ...
}

Vous pouvez aussi lancer plusieurs installations de Django sur le même site en précisant simplement de multiples entrées dans la directive fastcgi.server. Ajoutez un hôte FastCGI pour chacune.

Utiliser Django avec Apache sur un serveur mutualisé

Beaucoup d’hébergeurs de serveurs mutualisés n’autorisent pas à faire tourner votre propre démon serveur ou à éditer le fichier httpd.conf. Dans ce cas, il est toujours possible de faire tourner Django en utilisant les processus engendrés par le serveur web.

Note

Si vous utilisez les processus enfanté par le serveur, comme expliqué dans cette section, vous n’aurez pas besoin de démarrer le serveur FastCGI par vous même. Apache lancera de nombreux porcessus, en fonction des besoins.

Dans le répertoire web racine, ajoutez ceci à un fichier nommé .htaccess

AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]

Ensuite, créez un petit script qui indique à Apache comment lancer votre programme FastCGI. Créez un fichier, mysite.fcgi, et placez le dans votre répertoire web, en vous assurant qu’il soit exécutable.

#!/usr/bin/python
import sys, os

# Add a custom Python path.
sys.path.insert(0, "/home/user/python")

# Switch to the directory of your project. (Optional.)
# os.chdir("/home/user/myproject")

# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")
Redémarrer le serveur fils

Si vous modifiez du code Python sur votre site, vous devrez indiquer à FastCGI que le code a changé. Mais il n’est pas nécessaire de redémarrer Apache dans ce cas. Au lieu de cela, il suffit de recharger mysite.fcgi - ou éditer le fichier - de façon à ce que l’horodatage du fichier change. Lorsqu’Apache voit que le fichier a été mis à jour, il redémarrera votre application Django pour vous.

Si vous avez accès à la ligne de commande d’un système UNIX, vous pouvez accomplir ceci aisément en utilisant la commande touch:

touch mysite.fcgi

Montée en charge

À présent que vous savez comment faire tourner Django sur un unique serveur, regardons la façon dont vous pouver étendre une installation Django. Cette section explore la manière dont un site peut évoluer d’un unique serveur vers une grappe de serveurs de grande envergure capable de servir des millions de connexions à l’heure.

Il est important de noter, cependant, que presque tout site conséquent l’est de différente façons, aussi la montée en charge est tout sauf un opération «prêt à porter». Ce qui suit doit suffire à montrer les principes généraux, et lorsque c’est possible nous essaierons de préciser les endroits où ils est possible de faire des choix différents.

Tout d’abord, nous allons faire une hypothèse plutôt grossière et aborder exclusivement la montée en charge sous Apache et mod_python. Bien que nous connaissions de nombreux déploiements de plus ou moin de grande envergure utilisant FastCGI avec succès, nous sommes bien plus familier avec Apache.

Fonctionnement avec un unique serveur

La plupart des sites débutent sur une seule machine, avec une architecture qui ressemble à quelque chose comme la Figure 20-1.

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-1.png

Figure 20-1: configuration d’un serveur Django unique.

Ceci fonctionne parfaitement pour les sites de petite à moyenne taille, et reste relativement bon marché - vous pouvez avoir un site Django basé sur un seul serveur pour moin de 3000€.

Cependant, lorsque le traffic augmente, vous serez rapidement confronté à des problème d’allocation de ressources entre les différentes parties du logiciel. Les serveurs de base de données et les serveurs web adorent avoir tout le serveur à leur disposition, et donc lorsqu’ils tournent sur la même machine ils finissent souvent par se battre pour obtenir les mêmes ressources (RAM, CPU) qu’ils préféreraient monopoliser.

Ceci est aisément résolu en déplaçant le serveur de base de données sur une seconde machine, comme expliqué dans la section suivante.

Dissocier le serveur de base de données

En ce qui concerne Django, le fait de séparer le serveur de base de données est extremement simple: vous aurez juste à changer le paramètre DATABASE_HOST au profit de l’IP ou du DNS de votre serveur de base de données. Il est judicieux d’utiliser plutôt l’IP si cela est possible, puisque compter sur le DNS pour la connection entre votre serveru web et le serveur de base de données n’est pas recommandé.

Avec une serveur de base de données séparé, notre architecture ressemble à présent à la Figure 20-2.

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-2.png

Figure 20-2: Déplacer la base de données sur un serveur qui lui est dédié.

Ici nous allons commencer à travailler sur ce que l’on appelle couramment une architecture n-tiers. Ne soyez pas impressioné par ce mot à la mode - il fait simplement référence au fait que des «tiers» différent de la pile web sont séparés sur des machines physiquement dissociées.

À ce stade, si jamais vous prensez avoir besoin de vous étendre au-delà d’un seul serveur de base de données, c’est probablement une bonne idée de commencer à penser aux groupements de connexion ou à la réplication de bases de données. Malheureusement, ce livre n’ayant pas suffisament de place pour rendre justice à ces sujets, vous devrez consulter la documentation de votre base de données et votre communauté pour plus d’information.

Utliser un serveur de media dissocié

Nous avons toujours un gros problème laissé par le paramètrage en serveur unique: le service des médias depuis la même machine que celle qui gère le contenu dynamique. Ces deux activités sont optimales selon des circonstances différentes, et lorsqu’elles entre en collision sur la même machine vous n’arriverez jamais à obtenir de bonne performances. L’étape suivante est donc de séparer les médias - c’est à dire tout ce qui n’est pas généré par une vue Django - sur un serveur dédié à cela (voir la Figure 20-3).

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-3.png

Figure 20-3: Séparer le serveur de média.

Idéalement, ce serveur de médias doit tourner sur un serveur simplifié et optimisé pour le service des médias statiques. lighttpd et tux (http://www.djangoproject.com/r/tux/) sont tous deux d’excellents choix, mais des serveurs Apaches lourdement simplifié font aussi l’affaire.

Pour les sites ayant du contenu statique lourd (photos, videos, etc.), dissocié le serveur de media est doublement important et doit presqu’être la première étape de la montée en charge.

Cette étape peut être toutefois un peu laborieuse. Les administrateur Django doivent être capable d’ajouter des médias sur le serveur de médias (le paramètre MEDIA_ROOT contrôle l’emplacement de cette ajout). Si les médias résident sur un autre serveur, vous devrez quoi qu’il en soit trouver une façon pour que cette écriture se fasse au travers du réseau.

La manière la plus simple de faire ceci est d’utiliser NFS pour monter le répertoire médias du serveur de médias sur le(s) serveur(s) web. Si vous les montez au même endroit que celui pointé par MEDIA_ROOT, le téléchargement de média fonctionnera directement.

Implémenter la répartition de charge et la redondance

À ce stade, nous avons éclater les choses autant que possible. Cette configuration à trois serveurs doit pouvoir gérer une grosse quantité de traffic - nous avons fournis près de 10 millions de connexions par jour avec une architecture de la sorte - aussi si vous continuez à grandir, vous devrez commencer à ajouter de la redondance.

C’est une bonne chose à vrai dire. Un coup d’oeil à la Figure 20-3 vous indique que si même un seul de vos trois serveurs faillit, vous plantez intégralement votre site. Vous devez donc ajouter des serveurs redondant, pas seulement pour augmenter votre capacité, mais aussi pour augmenté la fiabilité.

Pour prendre cette exemple, considérons que le serveur web atteigne ses limites en premier. Il est facile d’avoir de multiples copies d’un site Django tournant sur du matériel différent - copiez simplement tout le code sur de multiples machines, et démarrez Apache sur les deux.

Cependant, vous aurez besoin d’une autre pièce matérielle pour répartir le trafic sur de multiple serveurs: un load balancer (répartiteur de charge). Vous pouvez achetez des répartiteurs de charge honéreux et propriétaires, mais il existe quelques répartiteurs de charge logiciels open-source de grande qualité.

Le mod_proxy d’Apache est une option, mais nous avons rencontrez Perlbal (http://www.djangoproject.com/r/perlbal/) tout simplement fantastic. C’est un répartiteur de charge et un reverse proxy écrit par les mêmes que ceux qui ont écrits memcached (lisez le Chapitre 13).

Note

Si vous utilisez FastCGI, vous pouvez obtenir la même répartition en séparant vos serveurs web frontaux et vos processus FastCGI en arrière plan sur sur des machines différentes. Le serveur frontal devient essentiellement le répartiteur de charge, et les processus de l’arrière-plan FastCGI remplacent les serveurs Apache/mod_python/Django.

Avec les serveurs web à présent mis en grappe, notre architecture évolutive commence à appaître comme étant un peu plus complexe, comme le montre la Figure 20-4.

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-4.png

Figure 20-4: Une configuration serveurs redondants et à répartition de charge.

Notez que dans le diagramme les serveurs web sont considérés comme des «cluster» afin d’indiquer que le nombre de serveurs est variable. Une fois que vous avez un répartiteur de charge en frontal, vous pouvez facilement ajouter et retirer des serveurs web sans une seconde d’interruption de service.

Devenir gros

À ce stade, les prochaines étapes sont des dérivées de la précédente:

  • lorsque vous aurez besoin de plus de performances en matière de base de données, vous devrez ajouter des serveurs de base de données répliqués. MySQL inclut des primites de réplications; les utilisateurs de PostgreSQL doivent regarder vers Slony (http://www.djangoproject.com/r/slony/) et pgpool (http://www.djangoproject.com/r/pgpool/) pour la réplication et les files de connection, respectivement.
  • Si un seul répartiteur de charge n’est pas suffisant, vous pouvez ajouter d’autres machines frontales et répartir entre elles en utilisant l’allocation circulaire DNS.
  • Si un seul serveur de médias ne suffit pas, vous pouvez ajouter plus de serveurs de médias et répartir la charge avec votre grappe de répartition de charge.
  • Si vous avez besoin de plus de stockage du cache, vous pouvez ajouter des serveurs de cache dédiés.
  • à toutes ces étapes, si un cluster n’est pas performant, vous pouvez ajouter plus de serveur à la grappe.

Après quelques unes de ces itérations, une architecture de grande envergure peut ressembler à la Figure 20-5.

http://new-media.djangobook.com/content/en/1.0/chapter20/scaling-5.png

Figure 20-5. Un exemple de configuration de Django à grande échelle.

Bien que nous n’ayons montrer que deux ou trois serveurs à chaque niveau, il n’y a pas de limitations fondamentale au nombre de serveur que vous pouvez ajouter.

Une fois que vous êtes arrivé à ce niveau, vous avez peu d’options. L’annexe A propose quelques informations de quelques développeurs responsable d’installations Django de grande envergure. Si vous prévoyez un site Django à fort trafic, cela vaut le coup de le lire.

Optimisation des performances

Si vous avez beaucoup d’argent, vous pouvez simplement continuer à ajouter du matériel pour résoudre les problèmes de croissance. Pour le reste d’entre nous, cependant, l’optimisation des performance est la meilleure solution.

Note

Par conséquent, si quelqu’un ayant des monceaux de liquidité est en train de lire ce livre, merci d’envisager une donation subtantielle au projet Django. Nous acceptons aussi les diamants bruts et les lingots d’or.

Malheureusement, l’optimisation des performance est plus un art qu’une science, et il est très difficile d’écrire sur ce sujet que sur la montée en charge. Si vous déployez sérieusement une application Django à grande échelle, vous devriez passer du temps à apprendre comment optimiser chaque élément de votre assemblage.

Les sections qui suivent, cependant, présentent quelques astuces d’optimisation spécifiques à Django que nous avons découvertes au fil du temps.

Rien ne vaut trop de RAM

Au moment de l’écriture de ce livre, la RAM vraiment chère coûte environ 200$ le giga - des cacahuètes comparé au temps passé à optimiser les choses par ailleurs. Achetez autant de RAM que vos moyens le permettent, puis achetez en un peu plus.

Des processeurs plus rapides n’améliorerons pas tellement plus les performances; la plupart des serveurs web passent 90% de leur temps à attendre des E/S disque. Dès que vous commencez à swaper, les performances vont se dégrader. Des disques plus rapides peuvent améliorer un peu la chose, mais ils sont plus honéreux que la RAM, ainsi donc cela ne compte pas vraiment.

Si vous avez de multiples serveurs, le premier endroit où ajouter votre RAM est dans les serveurs de base de données. Si vous le pouvez, achetez assez de RAM pour placer l’intégralité de votre base en mémoire. Ceci ne devrait pas être difficile. La base de données de LJWorld.com, constituée de près d’un demi millions d’articles depuis 1989, fait moins de 2GB.

Ensuite, ajoutez de la RAM à votre serveur web. La situation idéale est celle où aucun serveur de swap - jamais. Si vous atteignez ce point, vous devriez être en mesure de resister à un trafic normal.

Désactivez le Keep-Alive

Keep-Alive est une fonctionnalité de HTTP qui autorise les requêtes HTTP multiples à être servies sur une connection TCP unique, évitant ainsi la surcharge du TCP setup/teardown.

Ceci semble bon au premier abord, mais peut tuer les performances d’un site Django? Si vous servez correctement les médias depuis un serveur dissocié, chaque utilisateur naviguant sur votre site ne demandera qu’une page à votre serveur Django toutes les 10 secondes environ. Ceci laisse les serveurs HTTP attendre la prochaine requête keep-alive, alors qu’un serveur HTTP paresseux consomme la RAM qu’un serveur actif pourrait utiliser.

Utiliser memcached

Bien que Django supporte de nombreux moteur de cache différents, aucun d’entre eux n’est aussi proche de la rapidité de memcached. Si vous avez un site à fort trafic, ne perdez pas votre temps avec les autre moteurs - utilisez directement memcached.

Utiliser memcached souvent

Bien sûr, sélectionner memcached ne vous sert à rien si vous ne l’utilisez pas. Le Chapitre 13 est ici votre meilleur ami: apprenez comment utiliser le framework de cache de Django, et utiliser partout où c’est possible. Le cache agressif, préemptif, est habituellement la seule chose qui gardera un site disponible sous fort trafic.

Rejoindre la conversation

Chaque pièce de la pile Django - depuis Linux à Apache en passant pas PostgreSQL ou MySQL - possèdent de grandes communautés derrière elles. Si vous voulez vraiment gagner ce dernier 1% des capacités des serveurs, rejoignez la communauté open-source derrière votre logiciel et demandez de l’aide. La plupart des membres de la communauté des logiciels Libres seront heureux de vous aider.

N’hésitez pas à rejoindre la communauté Django. Vos humble auteurs (et traducteurs :)) sont simplement deux membres d’un groupe grandissant de développeurs Django incroyablement actifs. Notre communauté à une grande quantité d’expérience collective à offrir.

Et ensuite ?

Vous avez atteints la fin de notre programme régulier. Les annexes suivantes contiennent toutes du matériel de référence dont vous pourriez avoir besoin au fil de vos travaux sous Django.

Nous vous souhaitons le meilleur dans le fonctionnement de votre site sous Django, qu’il s’agisse d’un petit jouet pour vous et vos amis, ou u prochain Google.

<< précédentsuivant >>

Dernière modification: 2008-10-14 13:56:03.377612