Méthodes de débogage variées dans OpenResty

API7.ai

December 16, 2022

OpenResty (NGINX + Lua)

Dans le groupe de communication d'OpenResty, les développeurs posent souvent cette question : Comment déboguer dans OpenResty ? À ma connaissance, il existe quelques outils dans OpenResty qui prennent en charge le débogage par points d'arrêt, y compris un plugin dans VSCode, mais ils ne sont pas largement utilisés jusqu'à présent. Y compris l'auteur agentzh et quelques contributeurs que je connais, tout le monde utilise les méthodes les plus simples comme ngx.log et ngx.say pour faire du débogage.

Cela n'est pas convivial pour la plupart des débutants. Cela signifie-t-il que les nombreux mainteneurs principaux d'OpenResty n'ont que la méthode primitive d'impression de logs lorsqu'ils rencontrent un problème difficile ?

Bien sûr que non. Dans le monde d'OpenResty, SystemTap et les graphiques en flammes sont les outils standard pour traiter les problèmes difficiles et les problèmes de performance. Si vous avez une question à ce sujet sur une liste de diffusion ou un problème, le mainteneur du projet vous demandera de télécharger un graphique en flammes et de demander une description graphique plutôt que textuelle.

Dans les deux prochains articles, je vais vous parler du débogage et de l'ensemble d'outils qu'OpenResty a créé spécifiquement pour le débogage. Aujourd'hui, nous allons commencer par examiner ce qui est disponible pour déboguer les programmes.

Points d'arrêt et impressions de logs

Pendant longtemps dans mon travail, je me suis appuyé sur les fonctionnalités avancées de débogage de l'IDE (environnement de développement intégré) pour tracer les programmes, ce qui semblait naturel. Pour les problèmes qui peuvent être reproduits dans un environnement de test, peu importe leur complexité, je suis confiant de pouvoir en trouver la racine. La raison en est que le bug peut être reproduit à plusieurs reprises, et sa cause peut être trouvée en définissant des points d'arrêt et en imprimant des logs. Tout ce dont vous avez besoin, c'est de patience.

De ce point de vue, résoudre des bugs qui se reproduisent régulièrement dans un environnement de test est un travail physique. La plupart des bugs que je résous dans mon travail entrent dans cette catégorie.

Cependant, notez qu'il y a deux prérequis : un environnement de test et une reproduction stable. La réalité est toujours moins qu'idéale. Si le bug n'est reproduit que dans l'environnement de production, existe-t-il un moyen de le déboguer ?

Ici, je recommande un outil - Mozilla RR. Vous pouvez le considérer comme un répéteur, enregistrant le comportement du programme, puis en le rejouant à plusieurs reprises. Pour être honnête, que ce soit dans l'environnement de production ou de test, tant que vous pouvez enregistrer la "preuve" du bug, elle peut être utilisée comme "preuve en justice" pour l'analyser lentement.

Algorithme de recherche binaire et commentaires

Cependant, pour certains grands projets, par exemple, le bug peut provenir de l'un des multiples services, ou il peut y avoir un problème avec la requête SQL interrogeant la base de données, dans ce cas, même si le bug peut être reproduit de manière stable, vous ne pouvez pas être sûr de la partie où le bug s'est produit. Ainsi, les outils d'enregistrement comme Mozilla RR échouent.

À ce stade, vous pourriez vous souvenir de l'algorithme classique de "recherche binaire". Nous commentons d'abord la moitié de la logique dans le code, et si le problème persiste, le bug est dans le code non commenté, donc nous commentons la moitié restante de la logique et continuons la boucle. En quelques itérations, le problème est réduit à une taille complètement gérable.

Cette approche peut sembler un peu stupide, mais elle est efficace dans de nombreux scénarios. Bien sûr, à mesure que la technologie progresse et que la complexité du système augmente, nous recommandons d'utiliser une norme comme OpenTracing pour le traçage distribué.

OpenTracing peut être intégré dans diverses parties du système et rapporter la chaîne d'appels et le suivi des événements composés de plusieurs Spans au serveur via Trace ID pour analyse et présentation graphique. Cela peut aider les développeurs à trouver de nombreux problèmes cachés, et les données historiques seront sauvegardées afin que nous puissions les comparer et les consulter à tout moment.

De plus, si votre système est plus complexe, comme dans un environnement de microservices, alors Zipkin, Apache SkyWalking sont de bons choix.

Débogage dynamique

Les méthodes de débogage que j'ai décrites ci-dessus suffisent à résoudre la plupart des problèmes. Cependant, si vous rencontrez une panne qui ne se produit qu'occasionnellement en production, il faudra beaucoup de temps pour la suivre en ajoutant des logs et un suivi des événements.

Il y a quelques années, j'étais responsable d'un système qui épuisait les ressources de la base de données vers 1h00 du matin chaque jour et provoquait un effondrement total du système. À l'époque, nous avons vérifié les tâches planifiées dans le code pendant la journée, et la nuit, l'équipe attendait que le bug se reproduise dans l'entreprise, puis vérifiait l'état d'exécution des sous-modules lorsqu'il se reproduisait. Nous n'avons trouvé la cause du bug que la troisième nuit.

Mon expérience est similaire au contexte de plusieurs ingénieurs système Solaris qui ont créé Dtrace. À l'époque, les ingénieurs Solaris ont également passé des jours et des nuits à résoudre un problème de production bizarre, pour finalement découvrir que c'était parce qu'une configuration était mal écrite. Mais contrairement à moi, les ingénieurs Solaris ont décidé d'éviter complètement ce problème et ont inventé Dtrace, spécifiquement pour le débogage dynamique.

Contrairement aux outils de débogage statique comme GDB, le débogage dynamique peut déboguer des services en ligne. Le processus de débogage est non sensible et non intrusif pour le programme débogué, sans modification du code, et encore moins de redémarrage. Pour faire une analogie, le débogage dynamique est comme une radiographie, qui peut examiner le corps du patient sans avoir besoin de prélèvements sanguins et de gastroscopie.

Dtrace a été l'un des premiers frameworks de traçage dynamique, et son influence a conduit à l'émergence d'outils de débogage dynamique similaires sur d'autres systèmes. Par exemple, les ingénieurs de Red Hat ont créé Systemtap sur Linux, dont je vais parler ensuite.

Systemtap

Systemtap a son propre DSL, qui peut être utilisé pour configurer des points de sonde. Avant d'entrer dans plus de détails, installons Systemtap pour aller au-delà de l'abstrait. Ici, utilisez simplement le gestionnaire de paquets du système pour l'installer.

sudo apt install systemtap

Voyons à quoi ressemble un programme hello world écrit en Systemtap :

# cat hello-world.stp
probe begin
{
  print("hello world!")
  exit()
}

Cela semble facile, n'est-ce pas ? Vous devez utiliser les privilèges sudo pour l'exécuter.

sudo stap hello-world.stp

Il imprimera hello world!. Dans la plupart des scénarios, nous n'avons pas besoin d'écrire nos propres scripts stap pour faire l'analyse, car OpenResty a déjà beaucoup de scripts stap prêts à l'emploi pour faire l'analyse régulière, et je vous les présenterai dans le prochain article. Donc, aujourd'hui, nous devons avoir une brève compréhension des scripts stap.

Après quelques pratiques, revenons à notre concept, Systemtap fonctionne en convertissant le script stap ci-dessus en C et en exécutant le compilateur C du système pour créer le module kernel. Lorsque le module est chargé, il active tous les événements de sonde en accrochant le noyau.

Par exemple, begin s'exécutera au début de la sonde, et le end correspondant, donc le programme hello world ci-dessus peut également être écrit de la manière suivante :

probe begin
{
  print("hello ")
  exit()
}

probe end
{
print("world!")

Ici, je n'ai donné qu'une introduction très superficielle à Systemtap. Frank Ch. Eigler, l'auteur de Systemtap, a écrit un livre électronique Systemtap tutorial qui présente Systemtap en détail. Si vous souhaitez en apprendre plus et comprendre Systemtap en profondeur, je suggère de commencer par ce livre comme meilleur chemin d'apprentissage.

Autres frameworks de traçage dynamique

Systemtap ne suffit pas pour les ingénieurs d'analyse du noyau et de performance.

  1. Systemtap n'entre pas dans le noyau du système par défaut.
  2. Il fonctionne de manière à ce qu'il soit lent à démarrer et peut avoir un impact sur le fonctionnement normal du système.

eBPF (extended BPF) est une nouvelle fonctionnalité ajoutée au noyau Linux ces dernières années. Par rapport à Systemtap, eBPF a l'avantage d'être directement supporté par le noyau, de ne pas provoquer de plantages, et de démarrer rapidement. En même temps, il n'utilise pas de DSL, mais directement la syntaxe C, donc il est beaucoup plus facile à démarrer.

En plus des solutions open source, VTune d'Intel est également l'un des meilleurs outils. Son interface intuitive et sa présentation des données vous permettent d'analyser les goulots d'étranglement de performance sans écrire de code.

Graphique en flammes

Enfin, rappelons-nous du graphique en flammes mentionné dans l'article précédent. Comme nous l'avons mentionné précédemment, les données générées par des outils comme perf et Systemtap peuvent être affichées de manière plus visuelle en utilisant le graphique en flammes. Le diagramme suivant est un exemple de graphique en flammes.

graphique en flammes

Dans le graphique en flammes, la couleur et l'ombre des blocs de couleur n'ont pas de signification, juste pour faire une simple distinction entre les différents blocs de couleur. Le graphique en flammes est une superposition des données échantillonnées à chaque fois, donc les données utilisateur sont la largeur et la longueur des blocs.

Pour le graphique en flammes sur le CPU, la largeur du bloc de couleur est le pourcentage de temps CPU occupé par la fonction : plus le bloc est large, plus la perte de performance est grande. S'il y a un pic plat, c'est là que se trouve le goulot d'étranglement de performance. La longueur du bloc de couleur, quant à elle, représente la profondeur de l'appel de fonction, avec la boîte supérieure montrant la fonction en cours d'exécution et toutes celles en dessous étant les appelants de cette fonction. Donc, la fonction en dessous est le supertype de la fonction au-dessus : plus le pic est haut, plus la fonction est appelée en profondeur.

Résumé

Il est essentiel de savoir que même une technique non intrusive comme le traçage dynamique n'est pas parfaite. Elle ne peut détecter qu'un processus individuel particulier ; en général, nous ne l'activons que brièvement pour utiliser les données échantillonnées pendant ce temps. Donc, si vous avez besoin de détecter sur plusieurs services ou pendant de longues périodes, vous avez toujours besoin d'une technique de traçage distribué comme opentracing.

Quels outils et techniques de débogage utilisez-vous dans votre travail régulier ? N'hésitez pas à laisser un commentaire et à discuter avec moi, et n'hésitez pas à partager cet article avec vos amis, afin que nous puissions apprendre et progresser ensemble.