Configurer le serveur applicatif (Gunicorn) â đ” Confirmé¶
Gunicorn est le serveur qui exĂ©cute lâapplication Django en production. Il reçoit les requĂȘtes HTTP (directement, ou via Nginx ou la plateforme dâhĂ©bergement), les confie Ă Django et renvoie les rĂ©ponses.
Il est indispensable en production, oĂč le serveur de dĂ©veloppement de Django
(runserver) ne doit pas ĂȘtre utilisĂ©. Gunicorn permet notamment :
de servir plusieurs visiteurs en mĂȘme temps, en rĂ©partissant les requĂȘtes entre plusieurs processus ;
de garder le site disponible, en relançant automatiquement un processus qui plante ou ne répond plus.
Il ne rend pas le chargement dâune page plus rapide en soi, mais ses rĂ©glages dĂ©terminent combien de requĂȘtes le site peut traiter Ă la fois : ils jouent donc sur la rĂ©activitĂ© du site lorsquâil reçoit beaucoup de visites, et sur la mĂ©moire utilisĂ©e par le serveur.
Sites Conformes fournit une configuration prĂȘte Ă lâemploi : la plupart des instances nâont rien Ă rĂ©gler. Cette page explique son fonctionnement et comment lâadapter, notamment lorsque la mĂ©moire du serveur est limitĂ©e.
OĂč se trouve la configuration¶
La configuration se trouve dans le fichier
gunicorn.conf.py
Ă la racine du dĂ©pĂŽt. Gunicorn le charge automatiquement lorsquâil est lancĂ©
depuis ce dossier, quel que soit le mode de déploiement : Procfile sur
Scalingo, entrypoint.sh avec Docker, service systemd ou just run_gunicorn.
Les valeurs de ce fichier peuvent ĂȘtre modifiĂ©es par des variables
dâenvironnement GUNICORN_* (voir RĂ©glages), sans toucher
au code.
Note
Les options passées en ligne de commande à Gunicorn sont prioritaires sur
le fichier gunicorn.conf.py. Par exemple, lâexemple de service systemd de la
page Sur un serveur Linux (VPS, dĂ©diĂ© ou interne) â đ” ConfirmĂ© passe --workers 3 : cette valeur remplace alors
GUNICORN_WORKERS. Ordre de priorité, du plus faible au plus fort :
gunicorn.conf.py(et donc les variablesGUNICORN_*quâil lit) ;la variable
GUNICORN_CMD_ARGS, si elle est définie ;les options de la ligne de commande.
Fonctionnement¶
Gunicorn sâorganise en deux niveaux :
Processus maĂźtre
(surveille, ne traite aucune requĂȘte)
â â
Worker 1 Worker 2 â processus indĂ©pendants,
(copie de lâapplication) (copie de lâapplication) chacun sa mĂ©moire
â â â â
thread thread thread thread â requĂȘtes traitĂ©es
en mĂȘme temps
Le processus maĂźtre dĂ©marre les workers, les surveille et en relance un sâil plante ou ne rĂ©pond plus.
Les workers sont des processus Python complets, qui contiennent chacun une copie de Django, de Wagtail et du code du site. Ce sont eux qui traitent les requĂȘtes.
Les threads permettent Ă un worker de traiter plusieurs requĂȘtes en mĂȘme temps.
Le nombre de requĂȘtes traitĂ©es simultanĂ©ment est donc : nombre de workers Ă nombre de threads.
Astuce
En Python, un seul thread dâun processus exĂ©cute du code Ă un instant donnĂ©. Les threads nâaccĂ©lĂšrent donc pas le calcul dâune page : ils sont utiles pendant les attentes (requĂȘtes Ă la base de donnĂ©es, appels Ă un service externe), pendant lesquelles un autre thread peut avancer. Ils ne servent que si le site reçoit souvent plusieurs requĂȘtes en mĂȘme temps.
Chargement anticipĂ© de lâapplication¶
La configuration active preload_app : le processus maĂźtre charge
lâapplication une seule fois, puis crĂ©e les workers en se dupliquant. Les
workers démarrent ainsi plus vite, ce qui accélÚre les déploiements et les
redémarrages.
Au dĂ©part, les workers partagent la mĂ©moire du processus maĂźtre. En Python, ce partage diminue au fil du temps, car le simple fait dâutiliser un objet le modifie en mĂ©moire. Il faut donc compter quâĂ terme, le processus maĂźtre et chaque worker occupent chacun une copie de lâapplication.
Réglages¶
Variable |
RĂŽle |
Défaut |
Effet sur la mémoire |
|---|---|---|---|
|
Nombre de workers. à défaut, |
|
Fort : chaque worker ajoute une copie complĂšte de lâapplication. |
|
Nombre de threads par worker, câest-Ă -dire de requĂȘtes quâun worker traite en mĂȘme temps. |
|
Fort sous charge : chaque requĂȘte en cours occupe de la mĂ©moire pendant la gĂ©nĂ©ration de la page. |
|
Délai (en secondes) au-delà duquel un worker qui ne répond plus est redémarré. |
|
Aucun. |
|
Nombre de requĂȘtes traitĂ©es par un worker avant quâil soit redĂ©marrĂ©. |
|
Bénéfique : remet réguliÚrement la mémoire du worker à zéro. |
|
Aléa ajouté à |
|
Aucun. |
Deux rĂ©glages sont fixĂ©s dans le code et ne dĂ©pendent dâaucune variable :
worker_class = "gthread": workers capables dâutiliser des threads ;preload_app = True: chargement anticipĂ© de lâapplication (voir ci-dessus).
Mémoire et taille du serveur¶
La mĂ©moire utilisĂ©e par Gunicorn dĂ©pend surtout du nombre de workers et du nombre de requĂȘtes traitĂ©es en mĂȘme temps :
mĂ©moire â processus maĂźtre
+ workers Ă (application + requĂȘtes simultanĂ©es par worker Ă mĂ©moire par requĂȘte)
La mĂ©moire nĂ©cessaire varie selon la taille du site et le contenu des pages. Ă titre dâexemple, sur une instance de production hĂ©bergĂ©e sur un conteneur Scalingo de 1 Go, avec 2 workers :
Threads par worker |
RequĂȘtes simultanĂ©es |
Mémoire constatée |
|---|---|---|
4 |
8 |
environ 800 Mo, plus du swap : la limite était atteinte |
2 |
4 |
environ 300 Ă 520 Mo selon le trafic, avec par moments un peu de swap |
1 |
2 |
environ 450 Mo, sans swap |
Avec 2 threads, la mémoire dépasse déjà par moments 512 Mo : ce réglage
convient Ă un conteneur de 1 Go, mais pas Ă un conteneur de 512 Mo. Câest
pourquoi la valeur par défaut de GUNICORN_THREADS est 1 : elle convient
aussi aux petits conteneurs (512 Mo et moins).
Recommandations¶
Gardez les valeurs par défaut tant que le site fonctionne correctement.
Si la mĂ©moire approche de la limite ou si le serveur utilise du swap, rĂ©duisez dâabord le nombre de workers, par exemple
GUNICORN_WORKERS=1sur un petit conteneur.Si le site est lent sous forte affluence et que la mémoire le permet, augmentez progressivement
GUNICORN_THREADSouGUNICORN_WORKERS, puis surveillez la mĂ©moire pendant quelques heures de trafic normal.AprĂšs chaque changement, comparez la mĂ©moire juste aprĂšs le redĂ©marrage et aprĂšs une Ă deux heures de trafic : les threads nâoccupent de mĂ©moire que lorsque plusieurs requĂȘtes arrivent en mĂȘme temps.
Modifier un réglage¶
Sur Scalingo¶
DĂ©finissez la variable, puis redĂ©marrez lâapplication : la modification dâune variable nâest prise en compte quâau dĂ©marrage suivant.
Depuis le tableau de bord Scalingo, ajoutez ou modifiez la variable dans lâonglet « Environnement » de votre application (voir Sur Scalingo (ou PaaS) â đą DĂ©butant), puis redĂ©marrez lâapplication depuis le tableau de bord.
En ligne de commande, lâĂ©quivalent est :
scalingo --app mon-site env-set GUNICORN_THREADS=1
scalingo --app mon-site restart
Pour revenir à la valeur par défaut :
scalingo --app mon-site env-unset GUNICORN_THREADS
scalingo --app mon-site restart
La mĂ©moire de lâapplication se suit dans le tableau de bord, onglet « Metrics », graphique « Memory â web » (mĂ©moire, swap et limite du conteneur).
Sur un serveur Linux ou avec Docker¶
Ajoutez la variable au fichier .env de lâinstance :
GUNICORN_THREADS=1
Puis redĂ©marrez lâapplication, par exemple sudo systemctl restart sites-conformes avec le service dĂ©crit dans Sur un serveur Linux (VPS, dĂ©diĂ© ou interne) â đ” ConfirmĂ©.
VĂ©rifiez aussi que la commande qui lance Gunicorn ne passe pas la mĂȘme option en ligne de commande, qui serait prioritaire (voir OĂč se trouve la configuration).
Voir aussi¶
RĂ©fĂ©rence des variables dâenvironnement, section « Serveur applicatif (Gunicorn) » ;
la documentation de Gunicorn pour la liste complÚte des réglages ;