[PYTHON] Serveur Web pour remplacer Apache: optimisation des performances uWSGI

Contexte

Je développe un serveur d'application pour certains jeux téléphoniques avec Python et Django, et j'utilise uWSGI comme serveur Web. uWSGI a trop de paramètres et il est difficile de savoir lequel choisir.

En fait, j'ai fait un test de charge, modifié divers paramètres et maintenant je peux obtenir des performances stables. Je voudrais partager comment je l'ai mesuré à ce moment-là et quels paramètres j'ai changé.

environnement

server.png

Outil de mesure du rendement

"Ne devine pas, mesure"

Il y a un mot, mais si vous ne pouvez pas le mesurer quoi qu'il arrive, vous ne savez pas s'il s'est amélioré. Les outils suivants ont été principalement utiles cette fois.

À propos d'uwsgitop

Les données de statistiques de performances peuvent être sorties sur le socket comme suit dans les paramètres du côté uWSGI.

stats = /var/run/uWSGI/projectname.stats.sock
memory-report = true

Si vous exécutez uWSGI top installé avec pip etc. comme suit, vous pouvez voir les statistiques en temps réel comme la commande unix top.

$ uwsgitop /var/run/uWSGI/projectname.stats.sock

Voici un exemple d'exécution. Dans cet état, il s'agit d'une unité de traitement, mais si vous appuyez sur a sur le clavier, vous pouvez également la voir dans une unité de thread.

uwsgitop.png

Paramètres UWSGI efficaces pour le réglage des performances définis cette fois

Options uWSGI a des valeurs pour divers fichiers de paramètres, mais il y a trop de paramètres à définir. Il est difficile de savoir au début si vous pouvez le faire. De plus, l'explication des options est simple, et l'auteur de uWSGI lui-même vous demande de regarder la source, donc ce sera difficile si vous ne l'avez jamais utilisé.

Ici, je voudrais augmenter les paramètres qui étaient efficaces lorsque je les ai réellement définis.

processes, threads

uWSGI peut spécifier le nombre de processus et de threads qui acceptent les demandes. L'uWSGI que nous développons a les paramètres suivants.

processes = 16
threads = 1

Je l'ai testé avec diverses combinaisons de processus et de threads, mais lorsque j'ai augmenté le nombre de threads, le nombre de changements de contexte a augmenté et le RPS géré était inférieur à la moitié.

vmstat_1.png


vmstat_2.png

À propos, lorsque le nombre de threads est égal à 1, même si les processus sont augmentés, il n'y a pas beaucoup de différence lorsque le nombre de cœurs est de 8 ou plus.

thunder-lock

Si vous utilisez un serveur Linux, vous devez d'abord définir cette option sur true comme indiqué ci-dessous.

thunder-lock = true

Pour plus de détails, voir ici, mais s'il est faux, il s'agit d'une requête à traiter dans plusieurs processus uWSGI. Sera biaisé.

uwsgitop_1.png


uwsgitop_2.png

max-requests, max-requests-delta

max-requests est un paramètre pour le nombre de requêtes que le processus recevra avant le rechargement. Il est défini comme suit.

max-requests = 6000

Au début du test de charge, cette valeur était une valeur élevée, elle n'a pas été rechargée et l'état d'utilisation de la mémoire était le suivant.

memory_1.png

En regardant comment la mémoire du processus uWSGI augmente, 6000 est approprié, donc je l'ai configuré de cette façon. Je pense qu'il est nécessaire de rechercher pourquoi la mémoire augmente, mais comme elle est rechargée une fois toutes les 6000 fois, il est jugé qu'il n'y a pas d'effet et elle est définie. Une fois rechargée, la mémoire sera libérée et elle sera dans le même état que lors de son démarrage initial.

J'ai oublié de prendre chaque processus, mais s'il est réglé correctement, la mémoire se stabilisera dans une certaine période comme indiqué ci-dessous.

memory_2.png

Cependant, notez que lorsque le processus redémarre, il ne pourra pas recevoir de nouvelles demandes pendant quelques secondes. Si vous appliquez la même valeur de max-requests à tous les processus, ils redémarreront presque tous en même temps et le serveur entier ne recevra pas de demandes pendant quelques secondes.

Pour éviter cela, la valeur max-requests-delta est définie comme suit.

max-requests-delta = 300

Il redémarrera avec cette différence pour chaque processus. Par exemple, si un processus redémarre à 6000, le processus suivant redémarre lorsqu'il reçoit 6300 demandes. En supposant que le RPS est d'environ 16 et que le processus est défini sur 16, un processus reçoit une demande toutes les secondes, il redémarre donc toutes les 300 secondes. Cela limitera le nombre de processus pouvant être redémarrés en même temps, évitant ainsi que le serveur dans son ensemble ne puisse recevoir de requêtes.

touch-reload, lazy-apps

Vous pouvez spécifier le chemin du fichier dans touch-reload et recharger uWSGI chaque fois que le paramètre est touché. Cependant, si vous le faites, le serveur entier ne pourra pas recevoir de demandes, vous pouvez donc définir des applications paresseuses afin qu'il puisse être rechargé séquentiellement.

Si lazy-apps est spécifié dans notre environnement, il ne convient pas pour la mise à jour immédiate, nous ne permettons donc pas d'attendre quelques secondes et de le configurer.

Résumé

Cette fois, nous avons vu les paramètres de uWSGI qui ont été réellement réglés. De plus, les paramètres suivants ont été définis, mais j'aimerais continuer à étudier plus avant et à améliorer les performances.

Recommended Posts

Serveur Web pour remplacer Apache: optimisation des performances uWSGI
Construction de serveur Web Linux (Ubuntu et Apache)
Un guide d'introduction à l'optimisation des performances des programmes
Source compile Apache2.4 (httpd 2.4.43) + PHP7.4 sous Linux pour construire un serveur Web --3 MySQL 8.0 introduction
Le débutant de la CTF a tenté de créer un serveur problématique (Web) [Problème]