Grafana, InfluxDB, deux balises et un montant. Ou comment calculer la somme des sous-groupes?


Bonjour Ă  tous!

Engagé dans des tests de performance. Et j'aime vraiment configurer la surveillance et profiter des métriques dans Grafana . Et la norme de stockage des métriques dans les outils de chargement est InfluxDB . Dans InfluxDB, vous pouvez enregistrer des métriques à partir d'outils populaires tels que:


En travaillant avec des outils de test de performances et leurs métriques, j'ai accumulé une sélection de recettes de programmation pour le bundle de Grafana et InfluxDB . Je propose de considérer un problÚme intéressant qui se pose lorsqu'il existe une métrique avec deux balises ou plus. Je pense que ce n'est pas rare. Et dans le cas général, la tùche ressemble à ceci: calculer la métrique totale pour un groupe, qui est divisée en sous-groupes .

Il y a trois options:


  1. Juste le montant regroupé par balise Type
  2. Chemin Grafana. Nous utilisons une pile de valeurs
  3. Somme des sommets avec sous-requĂȘte

Comment tout a commencé


Configuration de la surveillance du MBean JVM à l'aide de Jolokia , Telegraf , InfluxDB et Grafana . Et il a visualisé les métriques par pools de mémoire - combien de mémoire est allouée par chaque pool de mémoire dans HEAP et au-delà.

Graphiques sur les pools de mémoire JVM et l'activité du garbage collector de 13h00 de la veille à 01h00 de la nuit du jour (période de 12 heures). Ici vous pouvez voir que les pools de mémoire sont divisés en deux groupes: HEAP et NON_HEAP . Et que vers 17h00 il y avait la collecte des ordures, aprÚs quoi la taille des pools de mémoire a diminué: Pour métriques recueillir sur les pools de mémoire, je a précisé les paramÚtres suivants dans le Telegraf fichier de configuration : telegraf.conf






[outputs.influxdb]
  urls = ["http://influxdb_server:8086"]
  database = "telegraf"
  username = "login-InfluxDb"
  password = "*****"
  retention_policy = "month"
  influx_uint_support = false

[agent]
  collection_jitter = "2s"
  interval = "2s"
  precision = "s"

[[inputs.jolokia2_agent]]
  username = "login-Jolokia"
  password = "*****"
  urls = ["http://127.0.0.1:7777/jvm-service"]

[[inputs.jolokia2_agent.metric]]
  paths = ["Usage","PeakUsage","CollectionUsage","Type"]
  name = "java_memory_pool"
  mbean = "java.lang:name=*,type=MemoryPool"
  tag_keys = ["name"]

[[processors.converter]]
  [processors.converter.fields]
    integer = ["CollectionUsage.*", "PeakUsage.*", "Usage.*"]
    tag = ["Type"]

Et dans Grafana, j'ai construit une demande Ă  InfluxDB pour afficher dans les graphiques la valeur mĂ©trique maximale Usage.Committedpour une pĂ©riode de temps avec un pas $granularity(1m) et regroupĂ©e par deux balises Type(HEAP ou NON_HEAP) et name(Metaspace, G1 Old Gen, ...): La mĂȘme demande sous forme de texte, en tenant compte de toutes les variables de Grafana (attention Ă  l'Ă©chappement des valeurs des variables avec - c'est important pour que la requĂȘte fonctionne correctement):



:regex

SELECT max("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^${host:regex}$/ AND
    jolokia_agent_url =~ /^${jolokia:regex}$/ AND
    $timeFilter
GROUP BY
    "Type", "name", time($granularity)

La mĂȘme requĂȘte sous forme de texte, en tenant compte des valeurs spĂ©cifiques des variables Grafana :

SELECT max("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^serverName$/ AND
    jolokia_agent_url =~ /^http:\/\/127\.0\.0\.1:7777\/jvm-service$/ AND
    time >= 1583834400000ms and time <= 1583877600000ms
GROUP BY
    "Type", "name", time(1m)

Le regroupement par heure GROUP BY time($granularity)ou GROUP BY time(1m)permet de réduire le nombre de points sur le graphique. Pour une durée de 12 heures et un pas de regroupement de 1 minute, on obtient: 12 x 60 = 720 fois soit 721 points (le dernier point avec une valeur nulle).

N'oubliez pas que 721 est le nombre attendu de points en réponse aux demandes à InfluxDB avec les paramÚtres actuels pour l'intervalle de temps (12 heures) et l'étape de regroupement (1 minute).

Pool de mĂ©moire NON_HEAP: Metaspace (bleu) est en tĂȘte de la consommation de mĂ©moire Ă  20h00. Et selon HEAP: G1 Old Gen (jaune), il y a eu une petite surtension locale Ă  17h03. Et au moment de 20h00, au total, tous les pools NON_HEAP ont laissĂ© 172,5 MiB (113,2 + 45,9 + 13,4) et les pools HEAP 128 MiB (67 + 57 + 4).



N'oubliez pas les valeurs de 20:00: pools NON_HEAP 172,5 MiB et pools HEAP 128 MiB . Nous nous concentrerons sur ces valeurs Ă  l'avenir.

Dans le contexte de Type : nom , nous avons facilement obtenu la valeur métrique.
Dans le contexte de la balise de nom uniquement , la valeur métrique est également facile à obtenir, car tous les noms des pools de mémoire sont uniques et il suffit de ne laisser le regroupement des résultats que par nom .

La question demeure: comment obtenir quelle taille est allouée pour tous les pools HEAP et tous les pools NON_HEAP au total?

1. Juste le montant regroupé par balise Type


1.1. Somme regroupée par balise


La premiĂšre solution qui peut vous venir Ă  l'esprit est de regrouper les valeurs par la balise Type et de calculer la somme des valeurs dans chaque groupe. Une telle requĂȘte ressemblera Ă  ceci: Une reprĂ©sentation textuelle d'une demande de calcul de somme regroupĂ©e par balise Type avec toutes les variables Grafana :





SELECT sum("Usage.committed")
FROM "telegraf"."month"."java_memory_pool"
WHERE
    host =~ /^${host:regex}$/ AND
    jolokia_agent_url =~ /^${jolokia:regex}$/ AND
    $timeFilter
GROUP BY
    "Type"

Il s'agit d'une requĂȘte valide, mais elle ne renverra que deux points: la somme sera calculĂ©e avec le regroupement uniquement par la balise Type avec deux valeurs (HEAP et NON_HEAP). Nous ne verrons mĂȘme pas le calendrier. Il y aura deux points autonomes avec une Ă©norme somme de valeurs (plus de 3 TiB): Une telle somme ne convient pas, une ventilation en intervalles de temps est nĂ©cessaire.





1.2. Montant groupé par tag par minute


Dans la requĂȘte d'origine, nous avons regroupĂ© les mesures selon un intervalle de granularitĂ© $ personnalisĂ© . Faisons le regroupement maintenant par un intervalle personnalisĂ©.

Cette requĂȘte se rĂ©vĂ©lera, elle a ajoutĂ© GROUP BY time($granularity): Nous obtenons des valeurs gonflĂ©es, au lieu de 172,5 Mio par NON_HEAP, nous voyons 4,88 Gio: Étant donnĂ© que les mesures sont envoyĂ©es Ă  InfluxDB une fois toutes les 2 secondes (voir telegraf.conf ci-dessus), la somme des lectures en une minute ne donnera pas le montant dans le moment, et la somme de trente de ces montants. Nous ne pouvons pas non plus diviser le rĂ©sultat par la constante 30 . Étant donnĂ© que $ granularity est un paramĂštre, il peut ĂȘtre dĂ©fini sur 1 minute et 10 minutes. Et la valeur du montant va changer.











1.3. Tag groupé par seconde


Afin d'obtenir correctement la valeur métrique pour l'intensité de collecte métrique actuelle (2 secondes), vous devez calculer le montant pour un intervalle fixe qui ne dépasse pas l'intensité de collecte métrique.

Essayons d'afficher les statistiques avec un regroupement en quelques secondes. Ajouter au GROUP BYregroupement time(1s): Avec une si petite granularité, nous obtenons un grand nombre de points pour notre intervalle de temps de 12 heures (12 heures * 60 minutes * 60 secondes = 43 200 intervalles, 43 201 points par ligne, dont le dernier est nul): 43 201 points dans chaque ligne du graphique. Il y a tellement de points qu'InfluxDB formera une réponse pendant longtemps, Grafana prendra une réponse plus longtemps, puis le navigateur attirera un si grand nombre de points pendant longtemps.









Et pas à chaque seconde, il y a des points: les mesures ont été collectées toutes les 2 secondes, et regroupées par seconde, ce qui signifie que chaque deuxiÚme point sera nul. Pour voir une ligne fluide, configurez la connexion des valeurs non vides. Sinon, nous ne verrons pas les graphiques: auparavant, Grafana était tel que le navigateur se bloquait lors du dessin d'un grand nombre de points. Maintenant, la version de Grafana a la possibilité de dessiner plusieurs dizaines de milliers de points: le navigateur saute simplement certains d'entre eux, dessine un graphique en utilisant les données amincies. Mais le graphique est lissé. Les sommets sont affichés comme des sommets moyens.





Par conséquent, il y a un graphique, il est affiché avec précision, les mesures à 20h00 sont calculées correctement, les mesures dans la légende du graphique sont calculées correctement. Mais le graphique est lissé: les rafales n'y sont pas visibles avec une précision de 1 seconde. En particulier, la surtension HEAP à 17:03 a disparu du graphique, le graphique HEAP est trÚs lisse: le moins dans les performances se manifestera clairement sur un intervalle de temps plus long. Si vous essayez de construire un graphique en un mois (720 heures), et non en 12 heures, alors tout gÚlera avec une si petite granularité (1 seconde), il y aura trop de points. Et il y a un moins en l'absence de pics, un paradoxe - en raison de la grande précision d'obtention des métriques, nous obtenons une faible précision de leur affichage .





2. Chemin Grafana. Nous utilisons une pile de valeurs


Il n'a pas Ă©tĂ© possible de crĂ©er une solution simple et productive avec InfluxDB et le concepteur de requĂȘtes Grafana . Nous essaierons uniquement d'utiliser les outils Grafana pour rĂ©sumer les mĂ©triques affichĂ©es dans le graphique d'origine. Et oui, c'est possible!

2.1. Il suffit de faire une info-bulle Hover / valeur empilée: cummulative


Nous laisserons la demande de choix des mĂ©triques inchangĂ©e, la mĂȘme que dans la section «Comment tout a commencé»: les mĂ©triques seront regroupĂ©es par type et nom . Mais nous afficherons uniquement la balise Type dans les noms des graphiques : Et dans les paramĂštres de visualisation, nous regrouperons les mĂ©triques par piles Grafana : Tout d'abord, ajoutez la sĂ©paration de deux balises en deux piles A et B diffĂ©rentes, afin que leurs valeurs ne se croisent pas:













  1. Ajouter un remplacement de série / HEAP / Stack : A
  2. Ajouter un remplacement de série / NON_HEAP / Stack : B

Configurez ensuite la visualisation des métriques pour afficher les valeurs totales dans une info-bulle avec des graphiques:

  1. Stacking & Null value / Stack : On
  2. Info-bulle de survol / valeur empilée : cumulatif
  3. Infobulle / mode de survol : simple

En raison des différentes fonctionnalités de Grafana, vous devez effectuer des actions dans cet ordre. Si vous modifiez l'ordre des actions ou laissez certains champs avec des paramÚtres par défaut, quelque chose ne fonctionnera pas:

  • Stack A B Stacking & Null value / Stack: On, ;
  • Hover tooltip / Mode , Single, Hover tooltip .

Et maintenant, nous voyons beaucoup de lignes, telles que nous-mĂȘmes. Mais! Si vous survolez le NON_HEAP le plus haut , l'info-bulle affichera la somme des valeurs de tous les NON_HEAP . Le montant est considĂ©rĂ© comme vrai, dĂ©jĂ  par Grafana signifie : Et si vous survolez le graphique le plus haut avec le nom HEAP , nous verrons le montant par HEAP . Le graphique s'affiche correctement. MĂȘme la surtension HEAP Ă  17 h 03 est visible: officiellement, la tĂąche est terminĂ©e. Mais il y a des inconvĂ©nients - de nombreux graphiques supplĂ©mentaires sont affichĂ©s. Vous devez placer le curseur tout en haut. Et dans la lĂ©gende du graphique, non cumulative, mais des valeurs individuelles sont affichĂ©es, de sorte que la lĂ©gende est devenue inutile.











2.2. Valeur empilée: cumulative avec masquage des lignes intermédiaires


Corrigeons le premier inconvénient de la solution précédente: assurez-vous que les graphiques supplémentaires ne sont pas affichés.

Pour ça:

  1. Ajoutez de nouvelles mesures avec un nom différent et une valeur 0 aux résultats.
  2. Ajoutez de nouvelles mesures Ă  la pile A et Ă  la pile B , en haut de la pile.
  3. Cacher de l'Ă©cran - les lignes originales de HEAP et NON_HEAP .

Nous en ajoutons deux nouveaux aprĂšs la requĂȘte principale: la requĂȘte B pour la rĂ©ception d'une sĂ©rie avec les valeurs 0 et le nom [NON_HEAP] et la requĂȘte C pour la rĂ©ception d'une sĂ©rie avec les valeurs 0 et le nom [HEAP] . Pour obtenir 0, nous prenons dans chaque groupe de temps la premiĂšre valeur du champ «Usage.committed» et la soustrayons: first («Usage.committed») - first («Usage.committed») - nous obtenons un 0 stable. Les noms des graphiques sont modifiĂ©s sans perte de sens en raison des crochets: [NON_HEAP] et [HEAP] : [HEAP] et HEAP sont combinĂ©s en pile A , et cache aussi tous HEAP . [NON_HEAP]



et combiner NON_HEAP dans Stack B et cacher NON_HEAP : Obtenez le montant exact par [NON_HEAP] dans l'info - bulle au survol de la carte: Obtenez le montant exact par [HEAP] dans l'info - bulle au survol de la carte. Et mĂȘme toutes les rafales sont visibles: Et le planning se forme rapidement. Mais la lĂ©gende affiche toujours 0, la lĂ©gende est devenue inutile. Tout a fonctionnĂ©! Le vrai contournement passe par les piles de Grafana . C'est pour cette raison que l'article a Ă©tĂ© ajoutĂ© Ă  la catĂ©gorie Programmation anormale .















3. La somme des sommets avec la sous-requĂȘte


Puisque nous nous sommes déjà engagés dans la voie d'une programmation anormale avec un tas de Grafana et InfluxDB , continuons. Faisons en sorte qu'InfluxDB retourne un petit nombre de points et faisons apparaßtre la légende.

3.1 Somme des incréments de la somme cumulée des maxima


Explorons les possibilitĂ©s d' InfluxDB . Auparavant, j'ai souvent aidĂ© en prenant le dĂ©rivĂ© du montant cumulĂ©, nous allons donc essayer d'appliquer cette approche maintenant. Passons au mode d'Ă©dition manuelle des requĂȘtes: Faisons une telle requĂȘte:





SELECT sum("U") FROM (
        SELECT non_negative_difference(cumulative_sum(max("Usage.committed"))) AS "U" 
        FROM "month"."java_memory_pool" 
        WHERE 
            (
                "host" =~ /^${host:regex}$/ AND 
                "jolokia_agent_url" =~ /^${jolokia:regex}$/
            ) AND 
            $timeFilter 
        GROUP BY time($granularity), "Type", "name"
)
GROUP BY "Type", time($granularity)

Ici, la valeur maximale de la mĂ©trique dans le groupe par le temps est prise et la somme de ces valeurs Ă  partir du moment oĂč la rĂ©fĂ©rence commence, regroupĂ©es par les balises Type et name . En consĂ©quence, Ă  chaque instant du temps , il y aura une somme de toutes les indications par type ( HEAP ou NON_HEAP ) avec sĂ©paration par nom du pool, mais pas 30 valeurs sont additionnĂ©es, comme ce fut le cas dans la version 1.2, mais une seule est le maximum.

Et si nous prenons l'incrĂ©ment non_negative_difference d' un tel montant cumulĂ© pour la derniĂšre Ă©tape, nous obtenons la somme de tous les pools de donnĂ©es regroupĂ©s par type et balises de nom au moment oĂč l'intervalle de temps a commencĂ©.

Maintenant, pour obtenir le montant par balise uniquementTapez , sans regroupement par balise de nom , vous devez effectuer une demande de niveau supérieur avec des paramÚtres de regroupement similaires, mais sans regroupement par nom .

À la suite d'une requĂȘte aussi complexe, nous obtenons la somme de tous les types.

Horaire parfait. La somme des maxima est calculĂ©e correctement. Il existe une lĂ©gende avec les valeurs correctes, non nulles. Dans l'info-bulle, vous pouvez afficher toutes les mĂ©triques, pas seulement Single. MĂȘme les rafales HEAP s'affichent : Une chose mais - la demande s'est avĂ©rĂ©e difficile: la somme de l'incrĂ©ment de la somme cumulĂ©e des maxima avec une modification du niveau de regroupement.





3.2 Somme des sommets avec changement de niveau de regroupement


Pouvez-vous faire quelque chose de plus simple que dans la version 3.1? La boĂźte de Pandore est dĂ©jĂ  ouverte, nous sommes passĂ©s en mode d'Ă©dition de requĂȘte manuelle.

On soupçonne que le fait de recevoir une augmentation du montant cumulé conduit à un effet nul - l'un éteint l'autre. Débarrassez-vous de non_negative_difference (cumulative_sum (...)) .

Simplifiez la demande.

On laisse simplement la somme des maxima, avec une diminution du niveau de regroupement:

SELECT sum("A")
FROM (
    SELECT max("Usage.committed") as "A"
    FROM "month"."java_memory_pool" 
    WHERE
            (
                "host" =~ /^${host:regex}$/ AND 
                "jolokia_agent_url" =~ /^${jolokia:regex}$/
            ) AND 
            $timeFilter
    GROUP BY time($granularity), "Type", "name"
)
WHERE $timeFilter
GROUP BY time($granularity), "Type"

Il s'agit d'une requĂȘte simple et rapide qui ne renvoie que 721 points par sĂ©rie en 12 heures, lorsqu'elle est regroupĂ©e par minutes: 12 (heures) * 60 (minutes) = 720 intervalles, 721 points (dernier vide). Veuillez noter que le filtre horaire est dupliquĂ©. C'est dans la sous-requĂȘte et dans la demande de regroupement: Sans $ timeFilter, dans la demande de regroupement externe, le nombre de points retournĂ©s ne sera pas de 721 en 12 heures, mais plus. Puisque la sous-requĂȘte est regroupĂ©e pour l'intervalle de ... Ă  , et le regroupement d'une demande externe sans filtre sera pour l'intervalle de ... maintenant . Et si Ă  Grafana un intervalle de temps qui ne dure pas X heures est sĂ©lectionnĂ© (pas tel que to = now



), mais pour l'intervalle du passé ( à < maintenant ), des points vides avec une valeur nulle à la fin de la sélection apparaßtront.

Le graphique rĂ©sultant s'est avĂ©rĂ© ĂȘtre simple, rapide et correct. Avec une lĂ©gende qui affiche des mĂ©triques rĂ©capitulatives. Avec info-bulle pour plusieurs lignes Ă  la fois. Et aussi avec l'affichage de toutes les rafales de valeurs: Le rĂ©sultat est atteint!





Références (au lieu de références)


Distributions des outils utilisés dans l'article:



Documentation sur les capacités des outils utilisés dans l'article:
EssenceLa description
Politique de rétention , InfluxDB Data RetentionRetention policy montn 30 , JVM . auto, . « » telegraf.conf InfluxDB , Grafana
Telegraf / InfluxDB v1.x Output PluginTelegraf InfluxDB. telegraf.conf
Telegraf / agent / interval, 2 . « » telegraf.conf. «1.2. » «1.3. »
Java 8 / Interface MemoryPoolMXBeanMemoryPool, , bool, long. telegraf.conf int
Telegraf / Jolokia2 Input Pluginstelegraf.conf MBean-, InfluxDB
Telegraf / Converter Processortelegraf.conf, float int InfluxDB. Type Type,
Grafana / Variables / Advanced Formatting Options / RegexGrafana, Multiselect , , , ~ /^${}$/ — , ~ /^${:regex}$/
Grafana / Variables / Global Built-in Variables / The $timeFilter or $__timeFilter VariableGrafana- $timeFilter,
InfluxDB / MAX()MAX() InfluxDB 1.7,
InfluxDB / SUM()SUM() InfluxDB 1.7
InfluxDB / SubqueriesInfluxDB 1.7, 3
InfluxDB / Transformation / CUMULATIVE_SUM()CUMULATIVE_SUM(), InfluxDB, NON_NEGATIVE_DERIVATIVE()
InfluxDB / Transformation / NON_NEGATIVE_DERIVATIVE()NON_NEGATIVE_DERIVATIVE(), 3 . CUMULATIVE_SUM() — 3
Using Grafana’s Query Inspector to troubleshoot issuesQuery Inspector, , Grafana-
Grafana / Graph / Draw OptionsStack, Tooltip,
 «2. Grafana-way. »
Grafana / Graph / Series overrides( ) Grafana


La combinaison de Grafana et InfluxDB doit ĂȘtre bien connue des ingĂ©nieurs de test de performance. Et dans ce bundle, de nombreuses tĂąches simples sont trĂšs intĂ©ressantes et ne peuvent pas toujours ĂȘtre rĂ©solues par des mĂ©thodes de programmation normales.

Parfois , les compĂ©tences de programmation anormales peuvent ĂȘtre nĂ©cessaires avec les Grafana caractĂ©ristiques et les subtilitĂ©s de la InfluxDB requĂȘte langage .

Dans l'article, des mesures ont été prises en compte pour quatre options d'implémentation de la sommation d'une métrique regroupée par une balise, mais qui a plusieurs balises. La tùche était intéressante. Et il existe de nombreuses tùches de ce type.

Je prépare un rapport sur les subtilités de la programmation avec Grafana et InfluxDB. Je publierai périodiquement des documents sur ce sujet. En attendant, je serai heureux de vos questions sur l'article actuel.

All Articles