TSDB-analys i Prometheus 2

TSDB-analys i Prometheus 2

Tidsseriedatabasen (TSDB) i Prometheus 2 är ett utmärkt exempel på en ingenjörslösning som erbjuder stora förbättringar jämfört med v2-lagringen i Prometheus 1 när det gäller dataackumuleringshastighet, utförande av frågor och resurseffektivitet. Vi implementerade Prometheus 2 i Percona Monitoring and Management (PMM) och jag fick möjlighet att förstå prestandan för Prometheus 2 TSDB. I den här artikeln kommer jag att prata om resultaten av dessa observationer.

Genomsnittlig arbetsbelastning för Prometheus

För dem som är vana vid att hantera databaser för allmänna ändamål är den typiska Prometheus-arbetsbelastningen ganska intressant. Hastigheten för dataackumulering tenderar att vara stabil: vanligtvis skickar tjänsterna du övervakar ungefär samma antal mätvärden, och infrastrukturen förändras relativt långsamt.
Begäran om information kan komma från olika källor. Vissa av dem, till exempel varningar, strävar också efter ett stabilt och förutsägbart värde. Andra, som användarförfrågningar, kan orsaka skurar, även om detta inte är fallet för de flesta arbetsbelastningar.

Ladda test

Under testningen fokuserade jag på förmågan att samla data. Jag distribuerade Prometheus 2.3.2 kompilerad med Go 1.10.1 (som en del av PMM 1.14) på ​​Linode-tjänsten med detta skript: StackScript. För den mest realistiska lastgenereringen, använd detta StackScript Jag lanserade flera MySQL-noder med en rejäl belastning (Sysbench TPC-C Test), som var och en emulerade 10 Linux/MySQL-noder.
Alla följande tester utfördes på en Linode-server med åtta virtuella kärnor och 32 GB minne, som körde 20 belastningssimuleringar som övervakade tvåhundra MySQL-instanser. Eller, i Prometheus termer, 800 mål, 440 skrapningar per sekund, 380 tusen rekord per sekund och 1,7 miljoner aktiva tidsserier.

Design

Det vanliga tillvägagångssättet för traditionella databaser, inklusive den som används av Prometheus 1.x, är att minnesgräns. Om det inte räcker för att hantera belastningen kommer du att uppleva höga latenser och vissa förfrågningar kommer att misslyckas. Minnesanvändning i Prometheus 2 är konfigurerbar via nyckel storage.tsdb.min-block-duration, som bestämmer hur länge inspelningar kommer att sparas i minnet innan de spolas till disk (standard är 2 timmar). Mängden minne som krävs beror på antalet tidsserier, etiketter och skrapningar som läggs till den inkommande nettoströmmen. När det gäller diskutrymme siktar Prometheus på att använda 3 byte per post (sample). Å andra sidan är minneskraven mycket högre.

Även om det är möjligt att konfigurera blockstorleken, rekommenderas det inte att konfigurera den manuellt, så du tvingas ge Prometheus så mycket minne som det kräver för din arbetsbelastning.
Om det inte finns tillräckligt med minne för att stödja den inkommande strömmen av mätvärden, kommer Prometheus att falla ur minnet eller så kommer OOM-mördaren till det.
Att lägga till swap för att fördröja kraschen när Prometheus får slut på minne hjälper inte riktigt, eftersom användningen av den här funktionen orsakar explosiv minnesförbrukning. Jag tror att det har att göra med Go, dess sophämtare och hur den hanterar byte.
Ett annat intressant tillvägagångssätt är att konfigurera huvudblocket så att det spolas till disken vid en viss tidpunkt, istället för att räkna det från början av processen.

TSDB-analys i Prometheus 2

Som du kan se från grafen sker flushes till disk varannan timme. Om du ändrar parametern min-block-duration till en timme, kommer dessa återställningar att ske varje timme, med start efter en halvtimme.
Om du vill använda denna och andra grafer i din Prometheus-installation kan du använda denna instrumentbräda. Den var designad för PMM men passar med mindre ändringar i alla Prometheus-installationer.
Vi har ett aktivt block som kallas huvudblock som lagras i minnet; block med äldre data finns tillgängliga via mmap(). Detta eliminerar behovet av att konfigurera cachen separat, men innebär också att du måste lämna tillräckligt med utrymme för operativsystemets cache om du vill fråga data som är äldre än vad huvudblocket kan ta emot.
Detta innebär också att Prometheus virtuella minnesförbrukning kommer att se ganska hög ut, vilket inte är något att oroa sig för.

TSDB-analys i Prometheus 2

En annan intressant designpunkt är användningen av WAL (write ahead log). Som du kan se från lagringsdokumentationen använder Prometheus WAL för att undvika krascher. Specifika mekanismer för att garantera dataöverlevnad är tyvärr inte väldokumenterade. Prometheus version 2.3.2 spolar WAL till disk var 10:e sekund och det här alternativet är inte användarkonfigurerbart.

Packningar

Prometheus TSDB är designad som ett LSM-lager (Log Structured Merge): huvudblocket spolas med jämna mellanrum till disken, medan en komprimeringsmekanism kombinerar flera block tillsammans för att undvika att skanna för många block under frågor. Här kan du se antalet block som jag observerade på testsystemet efter en dags belastning.

TSDB-analys i Prometheus 2

Om du vill lära dig mer om butiken kan du undersöka filen meta.json som har information om vilka block som finns och hur de kom till.

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

Kompakteringar i Prometheus är kopplade till den tidpunkt då huvudblocket spolas till disken. Vid denna tidpunkt kan flera sådana operationer utföras.

TSDB-analys i Prometheus 2

Det verkar som om komprimeringarna inte är begränsade på något sätt och kan orsaka stora disk I/O-spikar under exekvering.

TSDB-analys i Prometheus 2

CPU-belastningsspikar

TSDB-analys i Prometheus 2

Naturligtvis har detta en ganska negativ inverkan på systemets hastighet och utgör också en allvarlig utmaning för LSM-lagring: hur gör man komprimering för att stödja höga förfrågningshastigheter utan att orsaka för mycket overhead?
Användningen av minne i komprimeringsprocessen ser också ganska intressant ut.

TSDB-analys i Prometheus 2

Vi kan se hur, efter komprimering, det mesta av minnet ändrar tillstånd från Cachad till Free: detta betyder att potentiellt värdefull information har tagits bort därifrån. Nyfiken på om den används här fadvice() eller någon annan minimeringsteknik, eller beror det på att cachen befriades från block som förstördes under komprimeringen?

Återhämtning efter ett misslyckande

Återhämtning från misslyckanden tar tid, och det av goda skäl. För en inkommande ström på en miljon poster per sekund fick jag vänta cirka 25 minuter medan återställningen utfördes med hänsyn till SSD-enheten.

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

Huvudproblemet med återställningsprocessen är hög minnesförbrukning. Trots att servern i en normal situation kan fungera stabilt med samma mängd minne, kan den kanske inte återställas om den kraschar på grund av OOM. Den enda lösningen jag hittade var att inaktivera datainsamling, ta upp servern, låta den återhämta sig och starta om med insamlingen aktiverad.

Värmer upp

Ett annat beteende att tänka på under uppvärmningen är förhållandet mellan låg prestanda och hög resursförbrukning direkt efter start. Under vissa, men inte alla starter, observerade jag en allvarlig belastning på CPU och minne.

TSDB-analys i Prometheus 2

TSDB-analys i Prometheus 2

Luckor i minnesanvändning indikerar att Prometheus inte kan konfigurera alla samlingar från början, och viss information går förlorad.
Jag har inte räknat ut de exakta orsakerna till den höga CPU- och minnesbelastningen. Jag misstänker att detta beror på skapandet av nya tidsserier i huvudblocket med hög frekvens.

CPU-belastningen ökar

Förutom komprimeringarna, som skapar en ganska hög I/O-belastning, märkte jag allvarliga toppar i CPU-belastningen varannan minut. Sprängningarna är längre när inflödet är högt och verkar vara orsakade av Gos sopsamlare, med åtminstone några kärnor som är fulladdade.

TSDB-analys i Prometheus 2

TSDB-analys i Prometheus 2

Dessa hopp är inte så obetydliga. Det verkar som att när dessa inträffar blir Prometheus interna ingångspunkt och mätvärden otillgängliga, vilket orsakar dataluckor under samma tidsperioder.

TSDB-analys i Prometheus 2

Du kan också märka att Prometheus-exportören stängs av i en sekund.

TSDB-analys i Prometheus 2

Vi kan märka samband med sophämtning (GC).

TSDB-analys i Prometheus 2

Slutsats

TSDB i Prometheus 2 är snabb, kan hantera miljontals tidsserier och samtidigt tusentals poster per sekund med hjälp av ganska blygsam hårdvara. CPU och disk I/O-användning är också imponerande. Mitt exempel visade upp till 200 000 mätvärden per sekund per använda kärna.

För att planera expansion måste du komma ihåg om tillräckliga mängder minne, och detta måste vara riktigt minne. Mängden använt minne som jag observerade var cirka 5 GB per 100 000 poster per sekund av den inkommande strömmen, vilket tillsammans med operativsystemets cache gav cirka 8 GB upptaget minne.

Naturligtvis finns det fortfarande mycket arbete att göra för att tämja CPU- och disk I/O-spikar, och det är inte förvånande med tanke på hur ung TSDB Prometheus 2 är jämfört med InnoDB, TokuDB, RocksDB, WiredTiger, men de hade alla liknande problem tidigt i sin livscykel.

Källa: will.com

Lägg en kommentar