Programmation et développement logiciel

Comment construire des outils d’observabilité à faible coût pour les systèmes à grande échelle ?

Brian Martin, d’IOP Systems, explique comment concevoir la mesure opérationnelle de manière à préserver la visibilité du système sans transformer le chemin d’exécution critique en goulot d’étranglement. Ses recommandations portent principalement sur les opérations atomiques, le partitionnement par processeur, l’indexation directe et l’acceptation d’une cohérence approximative lorsqu’elle convient mieux aux performances.

2026-09-03
6 min de lecture
18 vues
فريق تحرير certi.news
Comment construire des outils d’observabilité à faible coût pour les systèmes à grande échelle ?

L’exploitation de services en production nécessite de savoir ce qui s’y passe, mais l’ajout de métriques n’est pas gratuit. Dans une présentation publiée par InfoQ, Brian Martin, cofondateur d’IOP Systems, explique que la différence entre deux implémentations peut faire passer la mise à jour d’un compteur d’une opération coûtant environ 5 nanosecondes à une opération dépassant une microseconde. Avec les histogrammes, l’écart peut passer d’environ 7 nanosecondes à plusieurs dizaines de microsecondes lorsque les threads se concurrencent.

L’idée centrale de la présentation n’est pas de choisir une bibliothèque Rust particulière, mais de considérer la mesure comme une composante de la conception des performances. Une métrique placée dans un chemin appelé des millions de fois amplifie le moindre coût, tandis que l’absence de mesure rend plus difficiles le diagnostic de la lenteur, des incidents de production et l’optimisation des performances.

Commencer par comprendre le type de données et le coût de leur mise à jour

Martin distingue trois grands types de métriques : le compteur, qui ne diminue généralement pas, comme le nombre de requêtes ; la jauge, qui représente une valeur actuelle, comme la profondeur d’une file d’attente ; et l’histogramme, qui décrit la distribution des valeurs, comme les temps de réponse. Cette distinction est importante, car chaque type impose des opérations différentes et les histogrammes fournissent des informations qu’un simple compteur total ne peut pas donner.

Dans les cas les plus simples, un atomic fetch_add convient aux compteurs entiers. En revanche, les boucles de comparaison et d’échange, ou CAS, nécessitent généralement de réessayer lorsque plusieurs threads se disputent le même emplacement. Une grande partie du coût provient de la synchronisation des lignes de cache entre les cœurs. La présentation cite des mesures effectuées sur une machine AWS Graviton dotée de 32 unités virtuelles de traitement : le plafond théorique du traitement atteignait environ 119 millions de requêtes par seconde avec une mise à jour atomique peu coûteuse, contre environ 23 millions avec une implémentation plus coûteuse utilisant Prometheus.

Réduire la concurrence grâce au partitionnement par processeur

Lorsque tous les threads partagent un seul compteur, la ligne de cache circule constamment entre les cœurs. Martin propose plutôt de créer un compteur indépendant par processeur, de sorte que les opérations d’écriture soient presque sans concurrence, puis d’additionner les valeurs lors de la lecture. Cette approche augmente légèrement le coût de lecture, mais protège le chemin d’écriture critique, qui est emprunté à chaque requête.

Il faut ici prêter attention au phénomène de false sharing. Le fait que les compteurs soient logiquement indépendants ne suffit pas s’ils sont placés sur une seule ligne de cache : une ligne fait 64 octets, ce qui signifie que huit compteurs de type 64-bit peuvent s’y retrouver côte à côte. La présentation recommande donc de regrouper et de remplir les compteurs afin qu’ils occupent des lignes de cache distinctes. Selon les chiffres présentés, les performances théoriques peuvent passer d’environ 119 millions de requêtes par seconde avec le compteur atomique à environ 6,4 milliards de requêtes par seconde avec un partitionnement approprié.

Concevoir les histogrammes pour le chemin de mise à jour

Le coût d’un histogramme commence par la détermination du compartiment auquel appartient la valeur. La recherche linéaire dans une liste de compartiments est l’option la plus simple et la plus lente, tandis que la recherche binaire réduit le nombre de comparaisons mais reste liée au nombre de compartiments. L’alternative la plus rapide est l’indexation directe, qui calcule le numéro du compartiment à partir de la valeur au lieu de le rechercher.

Cette indexation implique des compromis. La division en intervalles linéaires est rapide, mais peut produire une erreur relative importante pour les petites valeurs. L’indexation logarithmique préserve mieux l’erreur relative, mais le calcul du logarithme lui-même est coûteux. Martin présente l’utilisation de plages externes fondées sur Log2, avec des sous-compartiments qui ajustent la précision, comme dans HDR Histogram et H2Histogram. Lors d’un test non atomique, la détermination du compartiment et la mise à jour ont pris environ 2,65 nanosecondes dans HDR Histogram et environ 2,15 nanosecondes dans H2Histogram.

Quand une cohérence approximative est-elle acceptable ?

Le coût d’un histogramme ne dépend pas uniquement de la méthode d’indexation. Certaines applications mettent à jour plusieurs valeurs atomiques par opération, utilisent CAS pour les sommes ou imposent un verrou afin d’obtenir une vue cohérente. La présentation indique que certaines implémentations ont dépassé deux microsecondes, voire atteint plusieurs dizaines de microsecondes avec 32 cœurs, tandis que l’implémentation fondée sur l’indexation directe et une seule mise à jour atomique se rapprochait du coût d’un compteur.

L’alternative est la cohérence approximative : certains compartiments peuvent changer pendant la lecture de l’histogramme, mais la différence entre deux lectures successives reste utile lorsque les métriques sont de toute façon approximatives. Ce n’est pas une règle générale : les systèmes qui ont besoin d’une vue parfaitement cohérente peuvent préférer la synchronisation malgré son coût.

La lecture éditoriale de certi.news

En pratique, ce qui change, c’est que la décision d’ajouter des métriques doit inclure la structure de mise à jour, et pas seulement les noms des métriques. Le compteur atomique, le partitionnement par processeur et l’indexation directe peuvent rendre la mesure utilisable dans les chemins sensibles, tandis que les histogrammes synchronisés ou extensibles dynamiquement peuvent imposer un coût élevé sous pression. La présentation ne propose pas une recette unique valable pour chaque bibliothèque ou service : elle montre que la flexibilité, la possibilité d’utiliser la bibliothèque dans d’autres projets, la cohérence et les performances sont des objectifs partiellement contradictoires. Il faut donc tester l’implémentation réelle avec les niveaux de concurrence et le volume de traitement visés, plutôt que de se fier au nom de la bibliothèque ou au résultat obtenu dans un état sans concurrence.

Martin présente également l’utilisation d’eBPF au moyen du projet Rezolus pour obtenir des métriques précises depuis le noyau Linux, notamment concernant l’ordonnanceur, les chemins d’appel système et la pile TCP, sans modifier le code du noyau. La question ouverte reste de déterminer le niveau de précision et de cohérence nécessaire dans chaque cas, et de savoir si le coût de lecture ou d’agrégation des différentes parties restera acceptable lors de la montée en charge du système.

Source de l’actualité
InfoQ - Architecture Articles
Ouvrir la source originale ↗
ف
Auteur

فريق تحرير certi.news

Dans la même catégorie

À lire également

Voir toutes les actualités