Analyse TSDB dans Prometheus 2

Analyse TSDB dans Prometheus 2

La base de données de séries chronologiques (TSDB) de Prometheus 2 est un excellent exemple de solution d'ingénierie qui offre des améliorations majeures par rapport au stockage v2 de Prometheus 1 en termes de vitesse d'accumulation de données, d'exécution de requêtes et d'efficacité des ressources. Nous implémentions Prometheus 2 dans Percona Monitoring and Management (PMM) et j'ai eu l'occasion de comprendre les performances de Prometheus 2 TSDB. Dans cet article, je parlerai des résultats de ces observations.

Charge de travail moyenne de Prometheus

Pour ceux qui sont habitués à gérer des bases de données à usage général, la charge de travail typique de Prometheus est assez intéressante. Le taux d'accumulation de données a tendance à être stable : généralement, les services que vous surveillez envoient à peu près le même nombre de métriques et l'infrastructure évolue relativement lentement.
Les demandes d’informations peuvent provenir de diverses sources. Certaines d’entre elles, comme les alertes, visent également une valeur stable et prévisible. D'autres, comme les demandes des utilisateurs, peuvent provoquer des salves, bien que ce ne soit pas le cas pour la plupart des charges de travail.

Test de charge

Lors des tests, je me suis concentré sur la capacité à accumuler des données. J'ai déployé Prometheus 2.3.2 compilé avec Go 1.10.1 (dans le cadre de PMM 1.14) sur le service Linode en utilisant ce script : StackScript. Pour la génération de charge la plus réaliste, en utilisant ceci StackScript J'ai lancé plusieurs nœuds MySQL avec une charge réelle (Sysbench TPC-C Test), chacun émulant 10 nœuds Linux/MySQL.
Tous les tests suivants ont été effectués sur un serveur Linode doté de huit cœurs virtuels et de 32 Go de mémoire, exécutant 20 simulations de charge surveillant deux cents instances MySQL. Soit, en termes de Prometheus, 800 cibles, 440 grattages par seconde, 380 1,7 enregistrements par seconde et XNUMX million de séries temporelles actives.

Conception

L'approche habituelle des bases de données traditionnelles, y compris celle utilisée par Prometheus 1.x, consiste à limite de mémoire. Si cela ne suffit pas à gérer la charge, vous rencontrerez des latences élevées et certaines requêtes échoueront. L'utilisation de la mémoire dans Prometheus 2 est configurable via une clé storage.tsdb.min-block-duration, qui détermine la durée pendant laquelle les enregistrements seront conservés en mémoire avant d'être transférés sur le disque (la valeur par défaut est de 2 heures). La quantité de mémoire requise dépendra du nombre de séries temporelles, d’étiquettes et de scrapes ajoutés au flux entrant net. En termes d'espace disque, Prometheus vise à utiliser 3 octets par enregistrement (échantillon). En revanche, les besoins en mémoire sont bien plus élevés.

Bien qu'il soit possible de configurer la taille du bloc, il n'est pas recommandé de la configurer manuellement, vous êtes donc obligé de donner à Prometheus autant de mémoire que nécessaire pour votre charge de travail.
S'il n'y a pas assez de mémoire pour prendre en charge le flux de métriques entrant, Prometheus manquera de mémoire ou le tueur de MOO y parviendra.
Ajouter un swap pour retarder le crash lorsque Prometheus manque de mémoire n'aide pas vraiment, car l'utilisation de cette fonction entraîne une consommation explosive de mémoire. Je pense que cela a quelque chose à voir avec Go, son garbage collector et la façon dont il gère le swap.
Une autre approche intéressante consiste à configurer le bloc de tête pour qu'il soit vidé sur le disque à un certain moment, au lieu de le compter depuis le début du processus.

Analyse TSDB dans Prometheus 2

Comme vous pouvez le voir sur le graphique, les vidages sur le disque se produisent toutes les deux heures. Si vous modifiez le paramètre min-block-duration sur une heure, ces réinitialisations se produiront toutes les heures, en commençant après une demi-heure.
Si vous souhaitez utiliser ce graphique et d'autres dans votre installation Prometheus, vous pouvez utiliser ceci tableau de bord. Il a été conçu pour PMM mais, avec des modifications mineures, s'intègre dans n'importe quelle installation Prometheus.
Nous avons un bloc actif appelé bloc de tête qui est stocké en mémoire ; les blocs avec des données plus anciennes sont disponibles via mmap(). Cela élimine le besoin de configurer le cache séparément, mais signifie également que vous devez laisser suffisamment d'espace pour le cache du système d'exploitation si vous souhaitez interroger des données plus anciennes que ce que le bloc principal peut accueillir.
Cela signifie également que la consommation de mémoire virtuelle de Prometheus semblera assez élevée, ce qui n'est pas un sujet d'inquiétude.

Analyse TSDB dans Prometheus 2

Un autre point de conception intéressant est l’utilisation de WAL (write advance log). Comme vous pouvez le voir dans la documentation sur le stockage, Prometheus utilise WAL pour éviter les plantages. Les mécanismes spécifiques permettant de garantir la pérennité des données ne sont malheureusement pas bien documentés. Prometheus version 2.3.2 vide WAL sur le disque toutes les 10 secondes et cette option n'est pas configurable par l'utilisateur.

Compactages

Prometheus TSDB est conçu comme un magasin LSM (Log Structured Merge) : le bloc de tête est vidé périodiquement sur le disque, tandis qu'un mécanisme de compactage combine plusieurs blocs ensemble pour éviter d'analyser trop de blocs lors des requêtes. Ici vous pouvez voir le nombre de blocs que j'ai observés sur le système de test après une journée de chargement.

Analyse TSDB dans Prometheus 2

Si vous souhaitez en savoir plus sur le magasin, vous pouvez examiner le fichier méta.json, qui contient des informations sur les blocs disponibles et comment ils ont été créés.

{
       "ulid": "01CPZDPD1D9R019JS87TPV5MPE",
       "minTime": 1536472800000,
       "maxTime": 1536494400000,
       "stats": {
               "numSamples": 8292128378,
               "numSeries": 1673622,
               "numChunks": 69528220
       },
       "compaction": {
               "level": 2,
               "sources": [
                       "01CPYRY9MS465Y5ETM3SXFBV7X",
                       "01CPYZT0WRJ1JB1P0DP80VY5KJ",
                       "01CPZ6NR4Q3PDP3E57HEH760XS"
               ],
               "parents": [
                       {
                               "ulid": "01CPYRY9MS465Y5ETM3SXFBV7X",
                               "minTime": 1536472800000,
                               "maxTime": 1536480000000
                       },
                       {
                               "ulid": "01CPYZT0WRJ1JB1P0DP80VY5KJ",
                               "minTime": 1536480000000,
                               "maxTime": 1536487200000
                       },
                       {
                               "ulid": "01CPZ6NR4Q3PDP3E57HEH760XS",
                               "minTime": 1536487200000,
                               "maxTime": 1536494400000
                       }
               ]
       },
       "version": 1
}

Les compactages dans Prometheus sont liés au moment où le bloc de tête est vidé sur le disque. A ce stade, plusieurs opérations de ce type peuvent être réalisées.

Analyse TSDB dans Prometheus 2

Il semble que les compactages ne soient limités d’aucune manière et peuvent provoquer d’importants pics d’E/S disque lors de l’exécution.

Analyse TSDB dans Prometheus 2

Pics de charge du processeur

Analyse TSDB dans Prometheus 2

Bien sûr, cela a un impact plutôt négatif sur la vitesse du système, et pose également un sérieux défi pour le stockage LSM : comment effectuer le compactage pour prendre en charge des taux de requêtes élevés sans entraîner trop de frais généraux ?
L’utilisation de la mémoire dans le processus de compactage semble également très intéressante.

Analyse TSDB dans Prometheus 2

Nous pouvons voir comment, après le compactage, la majeure partie de la mémoire passe de l'état Cached à Free : cela signifie que des informations potentiellement précieuses en ont été supprimées. Curieux de savoir si c'est utilisé ici fadvice() ou une autre technique de minimisation, ou est-ce parce que le cache a été libéré des blocs détruits lors du compactage ?

Récupération après un échec

La récupération après un échec prend du temps, et pour cause. Pour un flux entrant d'un million d'enregistrements par seconde, j'ai dû attendre environ 25 minutes pendant que la récupération était effectuée en tenant compte du disque SSD.

level=info ts=2018-09-13T13:38:14.09650965Z caller=main.go:222 msg="Starting Prometheus" version="(version=2.3.2, branch=v2.3.2, revision=71af5e29e815795e9dd14742ee7725682fa14b7b)"
level=info ts=2018-09-13T13:38:14.096599879Z caller=main.go:223 build_context="(go=go1.10.1, user=Jenkins, date=20180725-08:58:13OURCE)"
level=info ts=2018-09-13T13:38:14.096624109Z caller=main.go:224 host_details="(Linux 4.15.0-32-generic #35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 x86_64 1bee9e9b78cf (none))"
level=info ts=2018-09-13T13:38:14.096641396Z caller=main.go:225 fd_limits="(soft=1048576, hard=1048576)"
level=info ts=2018-09-13T13:38:14.097715256Z caller=web.go:415 component=web msg="Start listening for connections" address=:9090
level=info ts=2018-09-13T13:38:14.097400393Z caller=main.go:533 msg="Starting TSDB ..."
level=info ts=2018-09-13T13:38:14.098718401Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536530400000 maxt=1536537600000 ulid=01CQ0FW3ME8Q5W2AN5F9CB7R0R
level=info ts=2018-09-13T13:38:14.100315658Z caller=web.go:467 component=web msg="router prefix" prefix=/prometheus
level=info ts=2018-09-13T13:38:14.101793727Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536732000000 maxt=1536753600000 ulid=01CQ78486TNX5QZTBF049PQHSM
level=info ts=2018-09-13T13:38:14.102267346Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536537600000 maxt=1536732000000 ulid=01CQ78DE7HSQK0C0F5AZ46YGF0
level=info ts=2018-09-13T13:38:14.102660295Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536775200000 maxt=1536782400000 ulid=01CQ7SAT4RM21Y0PT5GNSS146Q
level=info ts=2018-09-13T13:38:14.103075885Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536753600000 maxt=1536775200000 ulid=01CQ7SV8WJ3C2W5S3RTAHC2GHB
level=error ts=2018-09-13T14:05:18.208469169Z caller=wal.go:275 component=tsdb msg="WAL corruption detected; truncating" err="unexpected CRC32 checksum d0465484, want 0" file=/opt/prometheus/data/.prom2-data/wal/007357 pos=15504363
level=info ts=2018-09-13T14:05:19.471459777Z caller=main.go:543 msg="TSDB started"
level=info ts=2018-09-13T14:05:19.471604598Z caller=main.go:603 msg="Loading configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499156711Z caller=main.go:629 msg="Completed loading of configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499228186Z caller=main.go:502 msg="Server is ready to receive web requests."

Le principal problème du processus de récupération est la consommation élevée de mémoire. Bien que dans une situation normale, le serveur puisse fonctionner de manière stable avec la même quantité de mémoire, s'il tombe en panne, il risque de ne pas récupérer à cause du MOO. La seule solution que j'ai trouvée était de désactiver la collecte de données, d'ouvrir le serveur, de le laisser récupérer et de redémarrer avec la collecte activée.

Échauffement

Un autre comportement à garder à l’esprit lors de l’échauffement est la relation entre de faibles performances et une consommation élevée de ressources juste après le démarrage. Lors de certains démarrages, mais pas de tous, j'ai observé une charge importante sur le processeur et la mémoire.

Analyse TSDB dans Prometheus 2

Analyse TSDB dans Prometheus 2

Des lacunes dans l'utilisation de la mémoire indiquent que Prometheus ne peut pas configurer toutes les collections dès le départ et que certaines informations sont perdues.
Je n'ai pas compris les raisons exactes de la charge élevée du processeur et de la mémoire. Je soupçonne que cela est dû à la création de nouvelles séries chronologiques dans le bloc de tête à haute fréquence.

Augmentation de la charge du processeur

En plus des compactages, qui créent une charge d'E/S assez élevée, j'ai remarqué de sérieux pics de charge CPU toutes les deux minutes. Les rafales sont plus longues lorsque le flux d'entrée est élevé et semblent être causées par le garbage collector de Go, avec au moins certains cœurs complètement chargés.

Analyse TSDB dans Prometheus 2

Analyse TSDB dans Prometheus 2

Ces sauts ne sont pas si insignifiants. Il semble que lorsque cela se produit, le point d'entrée interne et les mesures de Prometheus deviennent indisponibles, provoquant des lacunes dans les données pendant ces mêmes périodes.

Analyse TSDB dans Prometheus 2

Vous pouvez également remarquer que l'exportateur Prometheus s'arrête pendant une seconde.

Analyse TSDB dans Prometheus 2

Nous pouvons remarquer des corrélations avec le garbage collection (GC).

Analyse TSDB dans Prometheus 2

Conclusion

TSDB dans Prometheus 2 est rapide, capable de gérer des millions de séries temporelles et en même temps des milliers d'enregistrements par seconde en utilisant un matériel assez modeste. L'utilisation du processeur et des E/S disque est également impressionnante. Mon exemple montrait jusqu'à 200 000 métriques par seconde par cœur utilisé.

Pour planifier une extension, vous devez vous rappeler d'une quantité de mémoire suffisante, et celle-ci doit être une mémoire réelle. La quantité de mémoire utilisée que j'ai observée était d'environ 5 Go pour 100 000 enregistrements par seconde de flux entrant, ce qui, avec le cache du système d'exploitation, donnait environ 8 Go de mémoire occupée.

Bien sûr, il reste encore beaucoup de travail à faire pour maîtriser les pics d'E/S du processeur et des disques, et cela n'est pas surprenant compte tenu de la jeunesse de TSDB Prometheus 2 par rapport à InnoDB, TokuDB, RocksDB, WiredTiger, mais ils avaient tous des performances similaires. problèmes au début de leur cycle de vie.

Source: habr.com

Ajouter un commentaire