Vous êtes ici : Accueil / 2014 / Mars / DeadlockDebugger : un outil d'analyse en temps réel d'une instance Zope

DeadlockDebugger : un outil d'analyse en temps réel d'une instance Zope

écrit le 07/03/2014 Par Gaël Le Mignot
DeadlockDebugger est un petit outil très pratique pour analyser en temps réel la raison de l'indisponibilité ou de la charge d'une instance Zope. Initialement écrit pour python 2.3/2.4 (Zope 2.7 à 2.10), Pilot Systems vient de le porter pour python 2.6/2.7 (Zope 2.12 et 2.13).

Introduction

DeadlockDebugger <http://plone.org/products/deadlockdebugger/> est un produit Zope permettant d'afficher, à un instant donné, l'état des différents threads d'une instance Zope.

Ce produit a été développé initialement par Nuxéo pour Python 2.3/2.4 (Zope de 2.7 à 2.10) et vient d'être porté par Pilot Systems pour Python 2.6 et 2.7 (Zope 2.12 et 2.13). La dernière version se trouve sur notre site de contributions.

Utilisation du produit

L'utilisation du produit se déroule en 3 étapes :

  1. Installer le produit, qui est un produit Zope 2 classique (pour une instance Zope classique, il suffit de le décompresser dans le répertoire Products/ de l'instance, pour une instance en buildout, voir cette documentation).
  2. Configurer le produit en éditant le fichier custom.py (ne pas oublier de renseigner un mot de passe dans SECRET) et redémarrer l'instance.
  3. Faire pointer le navigateur sur http://<host>:<port>/manage_debug_threads?<SECRET>.

On obtient alors une liste de l'activité des différents threads du Zope, du type (pour un Zope au repos) :

Threads traceback dump at 2014-03-03 16:09:17

Thread 140425561179904:
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZServerPublisher.py", line 25, in __init__
   name, a, b=accept()
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZRendezvous.py", line 73, in accept
   l.acquire()

Thread 140425569572608:
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZServerPublisher.py", line 25, in __init__
   name, a, b=accept()
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZRendezvous.py", line 73, in accept
   l.acquire()

Thread 140425586358016:
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZServerPublisher.py", line 25, in __init__
   name, a, b=accept()
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZRendezvous.py", line 73, in accept
   l.acquire()

Thread 140425577965312:
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZServerPublisher.py", line 25, in __init__
   name, a, b=accept()
 File "/usr/lib/zope2.13/lib/python/Zope2-2.13.20.egg/ZServer/PubCore/ZRendezvous.py", line 73, in accept
   l.acquire()

End of dump

Note : il est conseillé d'utiliser directement l'adresse du Zope, sans passer par d'éventuels frontaux (Apache, Squid/Varnish, Haproxy/Pound, ...) afin d'éviter une éventuelle congestion à leurs niveaux.

Attention : les informations contenues dans les tracebacks peuvent être confidentielles, il est donc important de bien garder le mot de passe secret.

Cas pratiques d'utilisation

Instance Zope bloquée

L'utilisation première, pour laquelle il a été inventé, est de trouver les raisons du blocage d'une instance Zope, qui ne répond plus aux demandes. DeadlockDebugger intercepte le ZPublisher très tôt et peut donc répondre même si les 4 (ou autres) threads du Zope sont tous bloqués.

Les cas de blocage d'un Zope peuvent être, par exemple :

  1. Un deadlock (interblocage) entre différentes lock, que ce soit du module threading de Python, des fichiers, des tables de base de données, ...
  2. Un appel récursif du Zope sur lui-même (via syndication RSS, XML-RPC, ...) qui épuise tous les threads.
  3. Une ressource externe (serveur LDAP, base de données SQL, source de flux RSS, API XML-RPC, SOAP ou REST, ...) qui ne répond pas aux requêtes.

Dans ce cas, afficher lors du blocage l'état des threads permettra de détecter facilement la cause du blocage.

Requête lente

La deuxième manière d'utiliser le produit est pour analyser et corriger, lors du développement, une requête particulièrement lente. En faisant un dump rapide de l'état du Zope pendant qu'il traite la requête, il est possible de voir à quel niveau survient la lenteur. Une ligne de commande du type :

while true; do lynx -dump http://<host>:<port>/manage_debug_threads?<SECRET> >> deadlock-debug.log ; done

Profilage d'une instance Zope

Une variante consiste à faire tourner, régulièrement, dans un cron (ou assimilé) un dump du DeadlockDebugger et d'analyser ensuite, après plusieurs jours, le contenu du log pour trouver les parties du code à optimiser en priorité (opération de profilage).

Attention tout de même, en raison du fonctionnement des threads sous Python, les appels systèmes (lecture/écriture, gestion des verrous, ...) seront surreprésentés dans le résultat du DeadlockDebugger. Il n'est pas pertinent de regarder à trop bas niveau (code interne de Zope) les résultats, mais plus au niveau intermédiaire (code des produits d'extension).

Conclusion

Ce petit produit très pratique permet d'adresser différents soucis d'exploitation ou de performance dans des développements Zope (ou Plone).

Actions sur le document