Cardinalité des métriques (Prometheus)
La cardinalité d’un système de métriques est le nombre de séries temporelles
uniques qu’il stocke. Dans Prometheus, chaque combinaison distincte de nom de
métrique et de valeurs de labels crée une série : une même métrique
http_requests_total déclinée sur 10 routes, 5 codes HTTP et 20 pods pèse
1 000 séries, pas une. C’est la grandeur qui dimensionne réellement un
serveur Prometheus — bien plus que le nombre de métriques déclarées.
Pourquoi elle explose
La cardinalité est multiplicative : ajouter un label multiplie le nombre de séries par le nombre de ses valeurs possibles. Le piège classique est le label à valeurs non bornées — identifiant de requête, adresse IP client, chemin d’URL contenant un identifiant. Chaque nouvelle valeur crée une série qui ne sera peut-être plus jamais mise à jour, mais que le serveur garde en mémoire tant qu’elle est considérée active. Sur Kubernetes, le renouvellement des pods produit le même effet : chaque redéploiement génère de nouveaux noms de pods, donc de nouvelles séries pour toutes les métriques qui portent ce label. Un histogramme aggrave le tout, puisqu’il émet une série par bucket.
Ce que ça coûte
Chaque série active occupe de la mémoire dans la tête de la TSDB (index, symboles, échantillons récents) — c’est le premier poste de consommation RAM d’un Prometheus. Au-delà de la mémoire, une cardinalité élevée ralentit les requêtes qui agrègent sur beaucoup de séries, alourdit les recording rules et, sur les offres managées ou mutualisées facturées à la série active, se paie directement sur la facture.
La mesurer et la contenir
Prometheus s’observe lui-même : prometheus_tsdb_head_series donne le total
de séries actives, et l’API TSDB (/api/v1/status/tsdb) liste les métriques
et labels les plus coûteux. En PromQL, topk(10, count by (__name__)({__name__=~".+"}))
identifie les métriques les plus grosses. Les leviers habituels : supprimer
ou réécrire des labels au scrape via metric_relabel_configs, abandonner
les métriques jamais requêtées, plafonner les dérives avec
sample_limit par cible, et pré-agréger par recording rules ce qui est
consulté sous forme agrégée. Le garde-fou le plus rentable reste en amont :
au moment d’instrumenter, refuser tout label dont on ne sait pas borner les
valeurs.