Lorsque vous exécutez la diversité d’applications nécessaires aujourd’hui pour alimenter nos nombreux outils et plateformes, le besoin d’une visibilité plus granulaire au niveau de l’application est devenu critique pour de nombreuses équipes d’ingénierie. eBPF est entré en jeu pour offrir une expansion significative des capacités traditionnelles de BPF, eBPF étend l’utilisation de BPF pour permettre bien plus que le simple traitement des paquets réseau. eBPF s’est transformé en un cadre polyvalent capable d’exécuter des programmes sandboxés dans le noyau, offrant un moyen sûr d’étendre les capacités du noyau sans modifier son code ou ajouter des modules noyaux.
Les programmes eBPF peuvent accéder au contexte de l’application (y compris l’exécution gérée, qui n’est pas limitée aux bibliothèques natives), et permettent aux développeurs d’attacher des programmes eBPF à divers crochets à l’intérieur du noyau Linux. Cela permet de surveiller les appels système, les événements réseau, voire le comportement spécifique à l’application sans avoir besoin d’une instrumentation traditionnelle lourde qui impose également un risque pour la stabilité de l’application. Cette capacité peut être exploitée pour analyser les performances de l’application, surveiller les menaces de sécurité et comprendre le comportement du système en temps réel, le tout avec un minimum de surcharge et une sécurité par conception grâce au vérificateur eBPF. Dans cet article, nous examinerons les deux méthodes les plus populaires pour implémenter l’instrumentation eBPF afin d’obtenir le contexte de l’application en temps d’exécution, en utilisant des sondes utilisateur et noyau - et comprendre comment chacune impacte les performances de l’application et le coût de calcul.
La technologie eBPF était autrefois principalement utilisée pour l’ingénierie de la visibilité et des performances, ainsi que pour des fins de mise en réseau (comme le filtrage des paquets et l’analyse du trafic réseau en utilisant XDP). Mais eBPF offre également aux développeurs un moyen puissant de collecter des données sur les applications (jusqu’au niveau de l’exécution des fonctions), avec une latence minimale.
En fonction du niveau de visibilité souhaité, eBPF peut être exploité pour une meilleure compréhension de :
La méthode d’instrumentation choisie jusqu’à présent a été les sondes noyau pour le premier niveau de visibilité, et les sondes utilisateur pour une visibilité plus approfondie du comportement au niveau de l’application. Cependant, l’instrumentation des sondes utilisateur présente ses propres défis uniques qui impactent directement les performances et le coût. Certains pourraient soutenir qu’elles ne conviennent pas du tout à la production.
Si nous examinons les benchmarks et les chiffres, nous pouvons constater une dégradation significative des performances lors de la mise en œuvre des sondes utilisateur pour la visibilité au niveau de l’application. Dans ce benchmark, vous pouvez voir les gains de performances pour le système de fichiers, le réseau et la surveillance de l’application lors de l’utilisation des sondes noyau par rapport aux sondes utilisateur.
La raison pour laquelle les sondes utilisateur sont la méthode la plus populaire pour la visibilité de l’application est que le noyau reste effrayant pour de nombreux développeurs, et il y a souvent une meilleure compréhension de l’espace utilisateur que du noyau Linux, en ce qui concerne les langages de programmation les plus populaires, de Python à JavaScript en passant par Golang. Une sonde utilisateur permet d’intégrer des programmes eBPF avec du code utilisateur, au prix d’un changement de contexte supplémentaire. Si vous êtes prêt à supporter le coût d’un changement de contexte supplémentaire, qui nuit aux performances (comme démontré dans le graphique ci-dessus), vous pourrez obtenir une visibilité dans presque n’importe quel morceau de code, là où vous en avez le plus besoin. Cependant, c’est exactement là que se situe le piège.
Ces sondes ne conviennent pas à tous les types d’applications, et elles nuisent vraiment aux performances dans certains cas d’utilisation - nous avons constaté une augmentation de 200 % par rapport à la même implémentation de kprobes. Cela est particulièrement vrai à grande échelle et pour des charges de travail intensives, et peut s’expliquer par les changements de contexte supplémentaires et la chaîne d’événements plus longue des uprobes (par rapport aux kprobes).
Lorsqu’il s’agit d’applications intensives en E/S, vous répétez les mêmes opérations de nombreuses fois par seconde ou par minute, en fonction de la fonction exécutée. Cela signifie qu’en fonction du niveau de visibilité requis, que ce soit au niveau de la fonction, ou de la traçabilité et du profilage : les exécutions ligne par ligne ont un coût très élevé du point de vue des performances de l’application. Cela est dû à la manière dont ces sondes fonctionnent, en nécessitant des changements de contexte supplémentaires à chaque événement.
Bien que nous comprenions les limitations des implémentations de sondes utilisateur eBPF pour la visibilité au niveau de l’application, la question demeure de savoir comment obtenir une plus grande visibilité en utilisant l’instrumentation des sondes noyau ? Jusqu’à présent, cette implémentation ne recevait que des valeurs et des adresses dans la mémoire réelle, cependant elles n’étaient pas vraiment capables d’accéder aux données au niveau de l’application jusqu’à présent. Jusqu’à Oligo.
Oligo a réalisé ce qui était auparavant possible uniquement en utilisant des sondes utilisateur et USDT (User Statically Defined Tracing) sans la charge opérationnelle des changements de contexte. Cette implémentation unique ne nécessite pas aux développeurs de changer leur façon de travailler, et n’impacte pas non plus les pipelines CI/CD ou les performances en temps d’exécution. Nous avons investi une grande partie de notre recherche et développement pour obtenir la même visibilité au niveau de l’application, sans le surcoût en performances.
Cette approche brille dans les environnements avec des runtimes gérés, tels que Python, JavaScript, Go, Java, PHP et Ruby, où les sondes noyau traditionnelles ne lisent généralement pas la mémoire virtuelle utilisée par ces langages, car ils gèrent leur propre mémoire de pile en espace utilisateur - ils incluent des compilateurs Just In Time (JAVA), un interprète (Python, PHP, Ruby, et plus). Cependant, cela pose moins de problèmes pour les langages natifs qui se compilent en code Assembleur - car leur mémoire de pile est directement accessible, telle quelle, aux programmes BPF.
Le choix entre les sondes en espace utilisateur et en espace noyau pour l’instrumentation eBPF se résume à équilibrer la visibilité et les performances. Alors que les sondes en espace utilisateur offrent des informations plus approfondies sur le comportement au niveau de l’application, elles s’accompagnent d’un coût de performances significatif, les rendant souvent inadaptées aux environnements de production. D’autre part, les sondes en espace noyau offrent une solution plus efficace avec moins d’impact sur les performances du système mais peuvent manquer de la visibilité détaillée requise pour certains cas d’utilisation. Vous pouvez accéder à la mémoire, mais vous n’avez aucune idée de ce qui se trouve à l’intérieur - comme le Chaos.
Chez Oligo, notre recherche a permis une approche novatrice de la visibilité au niveau de l’application, en utilisant les sondes noyau, il est désormais possible d’obtenir le meilleur des deux mondes : des informations complètes sans le surcoût en performances qui accompagne généralement les sondes en espace utilisateur. Cette approche permet aux équipes d’ingénierie de maintenir des performances et une efficacité élevées à travers les systèmes tout en acquérant la visibilité nécessaire dans les applications.
Lorsque vous envisagez eBPF pour la surveillance au niveau de l’application, il est essentiel de peser les compromis entre les sondes que nous utilisons et les crochets à l’intérieur de nos programmes eBPF. Pour les environnements de production où les performances sont critiques, les sondes en espace noyau offrent une solution pratique et efficace. Cependant, pour les scénarios nécessitant des informations plus approfondies sur l’application, les sondes en espace utilisateur peuvent encore être nécessaires, bien que avec prudence quant à leur impact sur les performances. En comprenant ces compromis et en utilisant les bons outils, les équipes d’ingénierie peuvent optimiser à la fois la visibilité et les performances de leurs applications en temps réel.