Surveillez les applications Web Python avec Prometheus

image.png

Dans cet article, un simple [Flask](http :) fonctionnant sur uWSGI + nginx //flask.pocoo.org/) Je vais vous expliquer comment j'ai fait cela avec un exemple qui rend l'application pleinement fonctionnelle dans la surveillance.

Un peu d'histoire

Prometheus était à l'origine un outil de surveillance dérivé de Google's Borgmon.

Dans un environnement natif, Borgmon s'appuie sur une découverte de services omniprésente et facile. Les services surveillés sont gérés par Borg et devraient être faciles à trouver. Par exemple, toutes les tâches sont exécutées dans un cluster d'utilisateurs spécifiques ou, pour des déploiements plus complexes, toutes les sous-tâches qui composent la tâche ensemble.

Chacun de ceux-ci pourrait être une cible unique pour que Borgmon récupère les données du point de terminaison / varz '', ainsi que du `` / metrics '' de Prometheus. Il s'agit généralement d'un serveur multithread écrit en C ++, Java, Go ou (moins fréquemment) Python.

Prométhée hérite de nombreuses hypothèses de Borgman sur son environnement. En particulier, la bibliothèque client suppose que les métriques proviennent de différentes bibliothèques et sous-systèmes de plusieurs threads d'exécution s'exécutant dans un espace d'adressage partagé, et du côté serveur, Prometheus a une cible. Supposons que vous soyez (probablement) un programme multithread.

Ne fais pas ça de cette façon

Ces hypothèses ont été brisées dans de nombreux déploiements non Google, en particulier dans le monde Python. Ici, nous distribuons la requête à plusieurs travailleurs (en utilisant, par exemple, Django ou Flask). WSGI Il est courant de s'exécuter sur un serveur d'applications (chaque worker est un processus, pas un thread).

Dans un déploiement simple du client Prometheus Python pour les applications Flask exécutées sous uWSGI, chaque requête du serveur Prometheus à `` / metrics '' atteint un processus de travail différent, chacun avec son propre compteur, Exportez l'histogramme, etc. Par conséquent, les données de surveillance deviennent des ordures.

En fait, chaque éraflure sur un compteur particulier renvoie la valeur d'un ouvrier, pas la totalité du travail. La valeur doit sauter et vous dire que rien n'est utile pour l'ensemble de l'application.

Solution

Amit Saha a le même problème et Various Solutions -with-prometheus.html) est discuté dans un article détaillé. Comme décrit dans l'un des articles, le client Prometheus Python comprend un mode multi-processus destiné à gérer cette situation, et un exemple de motivation du serveur d'application est gunicorn.

Cela fonctionne en partageant le répertoire mmap () 'd dictictionaries entre tous les processus de l'application. Faire. Chaque processus effectue ensuite un calcul pour renvoyer une vue partagée de la métrique à l'échelle de l'application lorsqu'elle est récupérée par Prometheus.

Cela a quelques «en-têtes» inconvénients mentionnés dans la documentation. Les exemples incluent le manque de métriques Python gratuites par processus, le manque de prise en charge complète de certains types de métriques et les types de jauge légèrement plus complexes.

Les configurations de bout en bout sont également difficiles. Voici ce dont vous avez besoin et comment vous avez réalisé chaque partie de votre environnement. Espérons que cet exemple complet sera utile à quiconque effectuera un travail similaire à l'avenir.

  1. Le répertoire partagé doit être passé au processus comme variable d'environnement prometheus_multiproc_dir``` Passez en utilisant l'option uWSGI env. Voir uwsgi.ini.

  2. Le répertoire partagé du client doit être effacé après le redémarrage de l'application. C'est un peu difficile à comprendre, mais dans les [Hardcoded Hooks] d'uWSGI (https://uwsgi-docs.readthedocs.io/en/latest/Hooks.html#the-hookable-uwsgi-phases) Utilisez un exec-asap pour exécuter le script shell immédiatement après avoir lu le fichier de configuration et avant de faire quoi que ce soit d'autre (https: //uwsgi-docs.readthedocs. io / en / latest / Hooks.html # exec-run-shell-commands). Voir uwsgi.ini. Ce script supprime et recrée le répertoire de données partagé du client Prometheus (https://github.com/hostedgraphite/pandoras_flask/blob/master/bin/clear_prometheus_multiproc). Pour vérifier les autorisations appropriées, exécutez uwsgi en tant que `` root '' sous Supervisor (http://supervisord.org/) et supprimez privs dans uwsgi (https :: //github.com/hostedgraphite/pandoras_flask/blob/master/conf/uwsgi.ini#L18).

  3. L'application doit définir le mode multi-processus du client Python. Cela a été fait principalement via Documents. https://github.com/prometheus/client_python#multiprocess-mode-gunicorn). Voir metrics.py. Il comprend également un middleware soigné (https://github.com/hostedgraphite/pandoras_flask/blob/master/pandoras_flask/metrics.py#L17) qui exporte les métriques Prometheus pour l'état de réponse et la latence. Veuillez noter que

  4. uWSGI doit configurer l'environnement de l'application pour que l'application soit chargée après fork (). Par défaut, uWSGI tente d'économiser de la mémoire en chargeant l'application puis `` fork () ''. Cela a certainement l'avantage de Copy on Write (https://en.wikipedia.org/wiki/Copy-on-write), qui peut économiser beaucoup de mémoire. Cependant, il semble interférer avec le fonctionnement en mode multi-processus du client. C'est peut-être parce que Lock before fork () est appliqué comme ça. [option paresseux-apps] de uWSGI (https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html?highlight=lazy-apps#preforking-vs-lazy-apps-vs-lazy) Vous pouvez l'utiliser pour charger l'application après la fourche, ce qui crée un environnement plus propre.

Celles-ci permettront aux points de terminaison `` / metrics '' des applications Flask exécutées sous uWSGI de fonctionner et d'être entièrement fonctionnels dans la démo pandoras_flask. Je pense que tu peux le faire.

Notez que la démo expose le point de terminaison métrique pour un autre port (https://github.com/hostedgraphite/pandoras_flask/blob/master/conf/nginx.conf#L28) à l'application appropriée. S'il vous plaît. Cela facilite l'accès à la surveillance sans que l'utilisateur n'y ait accès.

Dans votre déploiement, vous devriez pouvoir utiliser uwsgi_exporter pour obtenir plus de statistiques d'uWSGI lui-même.

Fonctionnalité

Dans le billet de blog de Saha (https://echorand.me/your-options-for-monitoring-multi-process-python-applications-with-prometheus.html), la solution recommandée est locale [statsd]( Il décrit un ensemble d'alternatives en poussant des métriques via (https://github.com/etsy/statsd). Ce n'est pas vraiment ce que nous aimons.

En fin de compte, tout exécuter sous une orchestration de conteneur comme kubernetes fournit un environnement natif où Prometheus brille, qui est le Python existant. C'est un grand pas vers l'obtention d'autres avantages dans la pile d'applications.

L'étape intermédiaire la plus prométhéenne consiste peut-être à enregistrer chaque sous-processus individuellement en tant que cible de grattage. Il s'agit de [django-prometheus](https://github.com/korfuri/django-prometheus/blob/master/documentation/exports.md#exporting-metrics-in-a-wsgi-application-with-multiple-processes- L'approche adoptée par processus), mais l'approche proposée par «plage de ports» est un peu plus compliquée.

Dans notre environnement, vous pouvez mettre en œuvre cette idée de la manière suivante (vous pouvez toujours l'avoir):

  1. Exécutez le serveur Web dans le thread de chaque processus, écoutez sur le port temporaire et traitez la requête / metrics.
  2. Enregistrez votre serveur Web et mettez régulièrement à jour son adresse (par exemple, nom d'hôte: 32769) avec un court chemin TTL etcd. J'utilise déjà etcd pour la plupart des besoins de découverte de services.
  3. Utilisez découverte de service basée sur des fichiers dans Prometheus pour identifier ces cibles et les frotter en tant qu'individus.

Je ne pense pas que cette approche soit plus compliquée que l'utilisation du mode multi-processus du client Python, mais elle a sa propre complexité.

Gardez à l'esprit que le fait d'avoir une cible par travailleur provoque une explosion de séries chronologiques. Par exemple, dans ce cas, une seule métrique d'histogramme par défaut qui suit les temps de réponse des clients Python sur huit travailleurs générera environ 140 séries temporelles individuelles avant de les multiplier par d'autres étiquettes à inclure. Ce n'est pas un problème que Prometheus gère, mais sachez que la mise à l'échelle peut augmenter (ou augmenter).

Résumé

Pour le moment, exporter des métriques de la pile d'applications Web Python standard vers Prometheus est un peu compliqué. Nous espérons que cet article sera utile à tous ceux qui souhaitent se familiariser avec l'application nginx + uwsgi + Flask existante.

Lors de l'exécution de plus de services sous l'orchestration de conteneurs (ce que nous essayons de faire), nous nous attendons à ce qu'il soit plus facile d'intégrer la surveillance Prometheus avec eux.

Un utilisateur bien établi de Prometheus est [Hosted Prometheus](https://try.metricfire.com/japan/?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Pandora's%20Flask%3A%20Monitoring%20a%20Python%20 Nous vous recommandons de jeter un œil aux services de 20 avec% 20 Prométhée). [Démo](https://calendly.com/metricfire-chatwithus/chat?utm_source=blog&utm_medium=Qiita&utm_campaign=Japan&utm_content=Pandora's%20Flask%3A%20Monitoring%20a%20Python%20web%20app%20with% nécessaire) N'hésitez pas à nous le dire.

Recommended Posts

Surveillez les applications Web Python avec Prometheus
Surveillez les applications Python avec l'APM de New Relic (Flask)
Web scraping avec python + JupyterLab
API Web avec Python + Falcon
Application Web avec Python + Flask ② ③
Web scraping débutant avec python
Rationalisez la recherche Web avec Python
Application Web avec Python + Flask ④
Premiers pas avec les applications Web Python
Web scraping avec Python Première étape
J'ai essayé webScraping avec python.
Surveillez les performances des applications Python avec Dynatrace ♪
Obtenez une capture d'écran Web avec python
Surveiller les pannes de Mojo avec Python et Skype
Premiers pas avec Python Web Scraping Practice
Démonisez une application Web Python avec Supervisor
Développer des applications Windows avec Python 3 + Tkinter (Préparation)
[Note personnelle] Scraping de pages Web en python3
Télécharger des fichiers sur le Web avec Python
Site de courses de chevaux Web scraping avec Python
Surveillez les mises à jour des pages Web avec LINE BOT
[Python] Une application web rapide avec Bottle!
Premiers pas avec Python Web Scraping Practice
Application Web facile avec Python + Flask + Heroku
Exécutez une application Web Python avec Docker
Créez un framework Web avec Python! (1)
Pratiquer le web scraping avec Python et Selenium
Scraping Web facile avec Python et Ruby
Créez un framework Web avec Python! (2)
[Pour les débutants] Essayez le web scraping avec Python
FizzBuzz en Python3
Grattage avec Python
Statistiques avec python
Grattage avec Python
Python avec Go
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
AES256 avec python
Testé avec Python
python commence par ()
avec syntaxe (Python)
Bingo avec python
Zundokokiyoshi avec python
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
Exécutez régulièrement le scraping WEB avec AWS-Lambda + Python + Cron
Contenu Web Python réalisé avec le serveur bon marché Lolipop
Introduction à Tornado (1): Framework Web Python démarré avec Tornado
La requête [Développement Web avec Python] est également redirigée
Démarrez un serveur Web Python simple avec Docker
Exécutez des applications Web Python avec NGINX + NGINX Unit + Flask
Développer des applications Windows avec Python 3 + Tkinter (fichier exe)
[python] Récupérez rapidement les métadonnées de la page Web avec lassie
[Version améliorée] Script pour surveiller le CPU avec Python
Lancer un serveur Web avec Python et Flask