Grafana, Influxdb et Telegraf permettent de moissonner vos mesures, mais parfois, il est necessaire d'aller plus loin et de créer son propre capteur.
Qu'il s'agisse d'améliorer les performances, benchmarker différentes pistes, auditer un soucis de perf ou tout simplement maintenir un service, il est important de pouvoir prendre son pouls.
Dans cet article nous vous présentons une maquette fonctionnelle complétant une stack standard de récupération et de visualisation de données pour l'adapter à vos besoins.
Grafana
Grafana est la réponse. Quel que soit vos choix, ils seront visualisés par Grafana au moins, et si vous en avez le besoin par d'autres outils.
Influxdata
Influxdata propose un ensemble cohérent d'outils pour collecter des données, les enregistrer, les requêter et finalement les afficher dans Grafana.
+----------+ +----------+ +---------+
| Telegraf +-->| Influxdb |<---+ Grafana |
+----------+ +----------+ +---------+
Telegraf
Telegraf est le collecteur d'Influxdata.
Architecturé sur un ensemble de plugins (aggregateurs, entrées, sorties, parseurs, processeurs, serialiseurs), ce sont ici les inputs qui nous interessent, et l'outil propose une longue liste d'inputs.
Une large partie des inputs est dédiée à un service précis.
Certains inputs "service" permettent de faire des requêtes libres, comme le propose redis et postgresql_extensible), mais rien pour les autres bases de données (mariadb a pourtant des trucs à dire).
Une partie des inputs est générique et permet de récupérer des informations variées :
procstat mais cgroup sera plus efficace
tail
exec
execd
Les inputs peuvent requêter des services distants :
http
prometheus
snmp
amqp_consumer
kafka_consumer
kinesis_consumer
mqtt_consumer
nats_consumer
nsq_consumer
postgresql_extensible
Les inputs peuvent être un service réseau, et attendre des métriques poussées par divers clients.
influxdb_listener
statsd (avec l'option tag, à la Datadog)
webhooks
riemann_listener
La liste des plugins est conséquente, mais il est quand même possible de ne pas trouver l'input qu'il nous faut.
Il est important d'instrumenter les applications que l'on développe, mais qu'en est-il pour un service existant ?
La sonde prometheus gagne son status de standard de fait et se trouve dans beaucoup de services modernes. Il existe des exporter tout prêt comme blackbox_exporter.
Par contre, coder un agent, juste pour exposer un endpoint prometheus n'est pas raisonnable.
Développer un agent qui va causer influxdb ou statsd est faisable, mais bon, on perds la centralisation du tempo de la mesure, et ça fera un systemd de plus.
La réponse officielle de telegraf pour récupérer des données spécifiques est exec ou mieux, execd.
exec va lancer une commande à chaque fois, et parser STDOUT. Simple, mais ça implique de lancer une commande plusieurs fois par minute.
execd va lui aussi lancer une commande, mais sans l'éteindre, et il redemandera à chaque fois une nouvelle réponse (toujours sur STDOUT).
La commande pourra réagir à une nouvelle ligne dans STDIN, un signal UNIX, ou se contenter d'écrire périodiquement de nouvelles choses dans STDOUT.
telegraf recommande la première approche : STDIN, qui fonctionnera aussi sur Windows.
Telegraf utilise des plugins pour parser les mesures, et son format de prédiléction est celui d'Influxdb, le line protocol.
Un service avec execd
Voici un exemple simple de l'utilisation d'execd avec python.
Configurer un inputs.execd est trivial, il faut choisir une commande, un signal et un format.
[[inputs.execd]]
## One program to run as daemon.
## NOTE: process and each argument should each be their own string
command = ["./my_command.py"]
## Define how the process is signaled on each collection interval.
## Valid values are:
## "none" : Do not signal anything. (Recommended for service inputs)
## The process must output metrics by itself.
## "STDIN" : Send a newline on STDIN. (Recommended for gather inputs)
## "SIGHUP" : Send a HUP signal. Not available on Windows. (not recommended)
## "SIGUSR1" : Send a USR1 signal. Not available on Windows.
## "SIGUSR2" : Send a USR2 signal. Not available on Windows.
signal = "STDIN"
## Delay before the process is restarted after an unexpected termination
restart_delay = "10s"
## Data format to consume.
## Each data format has its own unique set of configuration options, read
## more about them here:
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
data_format = "influx"
Le line-protocol est simplissime :
measurement[,tags] fields [timestamp]
measurement est le nom de la mesure.
Les tags sont un ensemble de clef=valeur séparés par des ,, qui permettront de regrouper/filtrer les mesures. Attention de ne jamais avoir de tag qui peut avoir un grand nombre de valeur (comme un id unique).
Les fields sont un ensemble de clef=nombre séparés par des ,.
timestamp n'est pas utilisé, ce sera à Telegraf de le gérer.
En python, l'implémentation du line-protocole va donner ça :
def marshal(dico):
return ",".join("=".join(t) for t in sorted(dico.items()))
# https://docs.influxdata.com/influxdb/v2.0/reference/syntax/line-protocol/
def write(writer, measurement, tags={}, fields={}):
"Writes to the Influxdb's line protocol"
print(measurement, ",", marshal(tags), "", marshal(fields),
sep='', file=writer)
La commande sera une boucle sur STDIN, qui ira chercher plusieurs mesures, et les affichera formaté sur STDOUT
for _ in sys.stdin: # execd protocol, newline trigger fresh stats
for tags, fields in fetch_my_measurements():
write(sys.stdout, "my_measurement", tags, fields)
Il faut bien sûr écrire son bout de code métier dans fetch_my_measurements, qui va yield des tags et des fields.
Telegraf permet simplement de tester un bout de config.
Il va lancer la récolte de mesure une fois, il l'affichera sur STDOUT ce qu'il enverrait à Influxdb (le line-protocol), sur STDERR les trucs bizarres, et stoppera. Attention à tester avec l'utilisateur telegraf (avec sudo ou gosu selon votre chapelle) si vous avez des contraintes de sécurité basées sur l'utilisateur.
telegraf --config my_command.conf --test
Au delà de d'influxData et Grafana
Il est aisé de récupérer des mesures précises pour comprendre le comportement de votre application en prod, de les stocker, et d'explorer depuis Grafana.
Vous pouvez maintenant partir à la recherche de nouvelles sources, et Linux (le kernel) bosse beaucoup sur ce sujet, cgroup est là depuis longtemps, mais ebpf devrait enfin amener les outils qui faisaient la réputation de Solaris.
Garder un oeil sur le sniffing réseau, avec pcap et ses successeurs, avec packetbeat comme hérault.
Niveau applicatif, statsd fait le job, prometheus est la norme inévitable, mais la fusion entre mesure, trace et log avance bien avec opentelemetry d'un coté, et l'omniprésent Grafana de l'autre (avec Loki qui vient de sortir sa 2.2, et Tempo qui souhaite piquer la place de Jaeger).
Et voilà !
Voila, vous êtes maintenant capable d'aller chercher les mesures nécessaires à la compréhension de vos soucis de performances, et de valider vos hypothèses en regardant ce que ça change au niveau des métriques.
Qu'il s'agisse d'améliorer les performances, benchmarker différentes pistes, auditer un soucis de perf ou tout simplement maintenir un service, il est important de pouvoir prendre son pouls.
Dans cet article nous vous présentons une maquette fonctionnelle complétant une stack standard de récupération et de visualisation de données pour l'adapter à vos besoins.
Grafana
Grafana est la réponse. Quel que soit vos choix, ils seront visualisés par Grafana au moins, et si vous en avez le besoin par d'autres outils.
Influxdata
Influxdata propose un ensemble cohérent d'outils pour collecter des données, les enregistrer, les requêter et finalement les afficher dans Grafana.
+----------+ +----------+ +---------+
| Telegraf +-->| Influxdb |<---+ Grafana |
+----------+ +----------+ +---------+
Telegraf
Telegraf est le collecteur d'Influxdata.
Architecturé sur un ensemble de plugins (aggregateurs, entrées, sorties, parseurs, processeurs, serialiseurs), ce sont ici les inputs qui nous interessent, et l'outil propose une longue liste d'inputs.
Une large partie des inputs est dédiée à un service précis.
Certains inputs "service" permettent de faire des requêtes libres, comme le propose redis et postgresql_extensible), mais rien pour les autres bases de données (mariadb a pourtant des trucs à dire).
Une partie des inputs est générique et permet de récupérer des informations variées :
procstat mais cgroup sera plus efficace
tail
exec
execd
Les inputs peuvent requêter des services distants :
http
prometheus
snmp
amqp_consumer
kafka_consumer
kinesis_consumer
mqtt_consumer
nats_consumer
nsq_consumer
postgresql_extensible
Les inputs peuvent être un service réseau, et attendre des métriques poussées par divers clients.
influxdb_listener
statsd (avec l'option tag, à la Datadog)
webhooks
riemann_listener
La liste des plugins est conséquente, mais il est quand même possible de ne pas trouver l'input qu'il nous faut.
Il est important d'instrumenter les applications que l'on développe, mais qu'en est-il pour un service existant ?
La sonde prometheus gagne son status de standard de fait et se trouve dans beaucoup de services modernes. Il existe des exporter tout prêt comme blackbox_exporter.
Par contre, coder un agent, juste pour exposer un endpoint prometheus n'est pas raisonnable.
Développer un agent qui va causer influxdb ou statsd est faisable, mais bon, on perds la centralisation du tempo de la mesure, et ça fera un systemd de plus.
La réponse officielle de telegraf pour récupérer des données spécifiques est exec ou mieux, execd.
exec va lancer une commande à chaque fois, et parser STDOUT. Simple, mais ça implique de lancer une commande plusieurs fois par minute.
execd va lui aussi lancer une commande, mais sans l'éteindre, et il redemandera à chaque fois une nouvelle réponse (toujours sur STDOUT).
La commande pourra réagir à une nouvelle ligne dans STDIN, un signal UNIX, ou se contenter d'écrire périodiquement de nouvelles choses dans STDOUT.
telegraf recommande la première approche : STDIN, qui fonctionnera aussi sur Windows.
Telegraf utilise des plugins pour parser les mesures, et son format de prédiléction est celui d'Influxdb, le line protocol.
Un service avec execd
Voici un exemple simple de l'utilisation d'execd avec python.
Configurer un inputs.execd est trivial, il faut choisir une commande, un signal et un format.
[[inputs.execd]]
## One program to run as daemon.
## NOTE: process and each argument should each be their own string
command = ["./my_command.py"]
## Define how the process is signaled on each collection interval.
## Valid values are:
## "none" : Do not signal anything. (Recommended for service inputs)
## The process must output metrics by itself.
## "STDIN" : Send a newline on STDIN. (Recommended for gather inputs)
## "SIGHUP" : Send a HUP signal. Not available on Windows. (not recommended)
## "SIGUSR1" : Send a USR1 signal. Not available on Windows.
## "SIGUSR2" : Send a USR2 signal. Not available on Windows.
signal = "STDIN"
## Delay before the process is restarted after an unexpected termination
restart_delay = "10s"
## Data format to consume.
## Each data format has its own unique set of configuration options, read
## more about them here:
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
data_format = "influx"
Le line-protocol est simplissime :
measurement[,tags] fields [timestamp]
measurement est le nom de la mesure.
Les tags sont un ensemble de clef=valeur séparés par des ,, qui permettront de regrouper/filtrer les mesures. Attention de ne jamais avoir de tag qui peut avoir un grand nombre de valeur (comme un id unique).
Les fields sont un ensemble de clef=nombre séparés par des ,.
timestamp n'est pas utilisé, ce sera à Telegraf de le gérer.
En python, l'implémentation du line-protocole va donner ça :
def marshal(dico):
return ",".join("=".join(t) for t in sorted(dico.items()))
# https://docs.influxdata.com/influxdb/v2.0/reference/syntax/line-protocol/
def write(writer, measurement, tags={}, fields={}):
"Writes to the Influxdb's line protocol"
print(measurement, ",", marshal(tags), "", marshal(fields),
sep='', file=writer)
La commande sera une boucle sur STDIN, qui ira chercher plusieurs mesures, et les affichera formaté sur STDOUT
for _ in sys.stdin: # execd protocol, newline trigger fresh stats
for tags, fields in fetch_my_measurements():
write(sys.stdout, "my_measurement", tags, fields)
Il faut bien sûr écrire son bout de code métier dans fetch_my_measurements, qui va yield des tags et des fields.
Telegraf permet simplement de tester un bout de config.
Il va lancer la récolte de mesure une fois, il l'affichera sur STDOUT ce qu'il enverrait à Influxdb (le line-protocol), sur STDERR les trucs bizarres, et stoppera. Attention à tester avec l'utilisateur telegraf (avec sudo ou gosu selon votre chapelle) si vous avez des contraintes de sécurité basées sur l'utilisateur.
telegraf --config my_command.conf --test
Au delà de d'influxData et Grafana
Il est aisé de récupérer des mesures précises pour comprendre le comportement de votre application en prod, de les stocker, et d'explorer depuis Grafana.
Vous pouvez maintenant partir à la recherche de nouvelles sources, et Linux (le kernel) bosse beaucoup sur ce sujet, cgroup est là depuis longtemps, mais ebpf devrait enfin amener les outils qui faisaient la réputation de Solaris.
Garder un oeil sur le sniffing réseau, avec pcap et ses successeurs, avec packetbeat comme hérault.
Niveau applicatif, statsd fait le job, prometheus est la norme inévitable, mais la fusion entre mesure, trace et log avance bien avec opentelemetry d'un coté, et l'omniprésent Grafana de l'autre (avec Loki qui vient de sortir sa 2.2, et Tempo qui souhaite piquer la place de Jaeger).
Et voilà !
Voila, vous êtes maintenant capable d'aller chercher les mesures nécessaires à la compréhension de vos soucis de performances, et de valider vos hypothèses en regardant ce que ça change au niveau des métriques.