TSDB-analyse in Prometheus 2

TSDB-analyse in Prometheus 2

De tijdreeksdatabase (TSDB) in Prometheus 2 is een uitstekend voorbeeld van een technische oplossing die grote verbeteringen biedt ten opzichte van de v2-opslag in Prometheus 1 op het gebied van de snelheid van gegevensaccumulatie, de uitvoering van query's en de efficiëntie van hulpbronnen. We waren Prometheus 2 aan het implementeren in Percona Monitoring and Management (PMM) en ik kreeg de kans om de prestaties van Prometheus 2 TSDB te begrijpen. In dit artikel zal ik het hebben over de resultaten van deze observaties.

Gemiddelde Prometheus-werklast

Voor degenen die gewend zijn om met databases voor algemene doeleinden om te gaan, is de typische Prometheus-werklast behoorlijk interessant. De snelheid waarmee gegevens worden verzameld is doorgaans stabiel: doorgaans verzenden de services die u monitort ongeveer hetzelfde aantal statistieken, en verandert de infrastructuur relatief langzaam.
Verzoeken om informatie kunnen uit verschillende bronnen komen. Sommigen daarvan, zoals alerts, streven ook naar een stabiele en voorspelbare waarde. Anderen, zoals gebruikersverzoeken, kunnen bursts veroorzaken, hoewel dit bij de meeste werkbelastingen niet het geval is.

Laadtest

Tijdens het testen concentreerde ik me op het vermogen om gegevens te verzamelen. Ik heb Prometheus 2.3.2 geïmplementeerd, gecompileerd met Go 1.10.1 (als onderdeel van PMM 1.14) op de Linode-service met behulp van dit script: StackScript. Gebruik dit voor de meest realistische belastinggeneratie StackScript Ik heb verschillende MySQL-nodes gelanceerd met een echte belasting (Sysbench TPC-C Test), die elk 10 Linux/MySQL-nodes emuleerden.
Alle volgende tests werden uitgevoerd op een Linode-server met acht virtuele cores en 32 GB geheugen, waarbij twintig belastingsimulaties werden uitgevoerd waarbij tweehonderd MySQL-instanties werden gemonitord. Of, in Prometheus-termen: 20 doelen, 800 scrapes per seconde, 440 duizend records per seconde en 380 miljoen actieve tijdreeksen.

ontwerp

De gebruikelijke aanpak van traditionele databases, inclusief die gebruikt door Prometheus 1.x, is om geheugenlimiet. Als dit niet voldoende is om de belasting aan te kunnen, zult u te maken krijgen met hoge latenties en zullen sommige verzoeken mislukken. Geheugengebruik in Prometheus 2 kan via een sleutel worden geconfigureerd storage.tsdb.min-block-duration, die bepaalt hoe lang opnames in het geheugen worden bewaard voordat ze naar schijf worden gespoeld (standaard is 2 uur). De benodigde hoeveelheid geheugen is afhankelijk van het aantal tijdreeksen, labels en scrapes dat aan de netto binnenkomende stroom wordt toegevoegd. In termen van schijfruimte streeft Prometheus ernaar om 3 bytes per record (sample) te gebruiken. Aan de andere kant zijn de geheugenvereisten veel hoger.

Hoewel het mogelijk is om de blokgrootte te configureren, wordt het niet aanbevolen om deze handmatig te configureren, waardoor u genoodzaakt bent Prometheus zoveel geheugen te geven als nodig is voor uw werklast.
Als er niet genoeg geheugen is om de binnenkomende stroom van statistieken te ondersteunen, raakt Prometheus uit het geheugen of komt de OOM-moordenaar erbij.
Het toevoegen van swap om de crash te vertragen wanneer Prometheus geen geheugen meer heeft, helpt niet echt, omdat het gebruik van deze functie een explosief geheugengebruik veroorzaakt. Ik denk dat het iets te maken heeft met Go, de afvalverzamelaar en de manier waarop het omgaat met ruilen.
Een andere interessante benadering is om het hoofdblok zo te configureren dat het op een bepaald tijdstip naar schijf wordt gespoeld, in plaats van dit vanaf het begin van het proces te tellen.

TSDB-analyse in Prometheus 2

Zoals u in de grafiek kunt zien, vinden er elke twee uur flushes naar de schijf plaats. Als u de parameter min-block-duration wijzigt in één uur, zullen deze resets elk uur plaatsvinden, beginnend na een half uur.
Als u deze en andere grafieken wilt gebruiken in uw Prometheus-installatie, kunt u deze gebruiken dashboard. Het is ontworpen voor PMM, maar past, met kleine aanpassingen, in elke Prometheus-installatie.
We hebben een actief blok genaamd hoofdblok dat in het geheugen is opgeslagen; blokken met oudere gegevens zijn beschikbaar via mmap(). Dit elimineert de noodzaak om de cache afzonderlijk te configureren, maar betekent ook dat u voldoende ruimte moet overlaten voor de cache van het besturingssysteem als u gegevens wilt opvragen die ouder zijn dan wat het hoofdblok kan bevatten.
Dit betekent ook dat het virtuele geheugenverbruik van Prometheus behoorlijk hoog zal lijken, en dat is niet iets om je zorgen over te maken.

TSDB-analyse in Prometheus 2

Een ander interessant ontwerppunt is het gebruik van WAL (write ahead log). Zoals u kunt zien in de opslagdocumentatie, gebruikt Prometheus WAL om crashes te voorkomen. Specifieke mechanismen om de overlevingskansen van gegevens te garanderen zijn helaas niet goed gedocumenteerd. Prometheus versie 2.3.2 spoelt WAL elke 10 seconden naar schijf en deze optie kan niet door de gebruiker worden geconfigureerd.

Verdichtingen

Prometheus TSDB is ontworpen als een LSM-opslag (Log Structured Merge): het hoofdblok wordt periodiek naar schijf gespoeld, terwijl een compactiemechanisme meerdere blokken combineert om te voorkomen dat er te veel blokken worden gescand tijdens query's. Hier kun je het aantal blokken zien dat ik op het testsysteem heb waargenomen na een dag laden.

TSDB-analyse in Prometheus 2

Als u meer wilt weten over de winkel, kunt u het meta.json-bestand bekijken, dat informatie bevat over de beschikbare blokken en hoe deze zijn ontstaan.

{
       "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
}

Verdichtingen in Prometheus zijn gekoppeld aan de tijd dat het hoofdblok naar de schijf wordt gespoeld. Op dit punt kunnen verschillende van dergelijke bewerkingen worden uitgevoerd.

TSDB-analyse in Prometheus 2

Het lijkt erop dat compacties op geen enkele manier beperkt zijn en tijdens de uitvoering grote schijf-I/O-pieken kunnen veroorzaken.

TSDB-analyse in Prometheus 2

CPU-belastingspieken

TSDB-analyse in Prometheus 2

Dit heeft uiteraard een nogal negatieve invloed op de snelheid van het systeem en vormt ook een serieuze uitdaging voor de LSM-opslag: hoe kan compactie worden uitgevoerd om hoge verzoeksnelheden te ondersteunen zonder al te veel overhead te veroorzaken?
Het gebruik van geheugen bij het compactieproces ziet er ook behoorlijk interessant uit.

TSDB-analyse in Prometheus 2

We kunnen zien hoe, na compactie, het grootste deel van het geheugen van status verandert van Cached naar Free: dit betekent dat potentieel waardevolle informatie daaruit is verwijderd. Benieuwd of het hier gebruikt wordt fadvice() of een andere minimalisatietechniek, of komt dit doordat de cache is bevrijd van blokken die tijdens het compacteren zijn vernietigd?

Herstel na een mislukking

Herstel van mislukkingen kost tijd, en met goede reden. Voor een inkomende stroom van een miljoen records per seconde moest ik ongeveer 25 minuten wachten terwijl het herstel werd uitgevoerd, rekening houdend met de SSD-schijf.

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."

Het grootste probleem van het herstelproces is het hoge geheugengebruik. Ondanks het feit dat de server in een normale situatie stabiel kan werken met dezelfde hoeveelheid geheugen, is het mogelijk dat deze bij een crash niet herstelt vanwege OOM. De enige oplossing die ik vond was het uitschakelen van het verzamelen van gegevens, het openen van de server, het laten herstellen en opnieuw opstarten met het verzamelen ingeschakeld.

Opwarmen

Een ander gedrag waarmee u rekening moet houden tijdens het opwarmen is de relatie tussen lage prestaties en een hoog verbruik van hulpbronnen direct na de start. Tijdens sommige, maar niet alle, starts merkte ik een ernstige belasting op de CPU en het geheugen.

TSDB-analyse in Prometheus 2

TSDB-analyse in Prometheus 2

Hiaten in het geheugengebruik geven aan dat Prometheus niet alle verzamelingen vanaf het begin kan configureren en dat bepaalde informatie verloren gaat.
Ik ben er nog niet achter wat de exacte redenen zijn voor de hoge CPU- en geheugenbelasting. Ik vermoed dat dit komt door het creëren van nieuwe tijdreeksen in het hoofdblok met een hoge frequentie.

CPU-belastingspieken

Naast de compacties, die een vrij hoge I/O-belasting veroorzaken, merkte ik elke twee minuten ernstige pieken in de CPU-belasting op. De bursts zijn langer als de invoerstroom hoog is en lijken te worden veroorzaakt door de garbage collector van Go, waarbij ten minste enkele kernen volledig zijn geladen.

TSDB-analyse in Prometheus 2

TSDB-analyse in Prometheus 2

Deze sprongen zijn niet zo onbelangrijk. Het lijkt erop dat wanneer deze zich voordoen, het interne toegangspunt en de metrieken van Prometheus niet meer beschikbaar zijn, waardoor gegevenslacunes ontstaan ​​tijdens dezelfde perioden.

TSDB-analyse in Prometheus 2

U kunt ook merken dat de Prometheus-exporteur gedurende één seconde wordt afgesloten.

TSDB-analyse in Prometheus 2

We kunnen correlaties opmerken met garbage collection (GC).

TSDB-analyse in Prometheus 2

Conclusie

TSDB in Prometheus 2 is snel en kan miljoenen tijdreeksen en tegelijkertijd duizenden records per seconde verwerken met behulp van redelijk bescheiden hardware. Het CPU- en schijf-I/O-gebruik is ook indrukwekkend. Mijn voorbeeld toonde tot 200 statistieken per seconde per gebruikte kern.

Om uitbreiding te plannen, moet u rekening houden met voldoende geheugen, en dit moet echt geheugen zijn. De hoeveelheid gebruikt geheugen die ik heb waargenomen was ongeveer 5 GB per 100 records per seconde van de inkomende stroom, wat samen met de cache van het besturingssysteem ongeveer 000 GB bezet geheugen opleverde.

Natuurlijk moet er nog veel werk worden verzet om CPU- en schijf-I/O-pieken te temmen, en dit is niet verrassend als je bedenkt hoe jong TSDB Prometheus 2 wordt vergeleken met InnoDB, TokuDB, RocksDB en WiredTiger, maar ze hadden allemaal vergelijkbare problemen vroeg in hun levenscyclus.

Bron: www.habr.com

Voeg een reactie