
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: . För den mest realistiska lastgenereringen, anvĂ€nd detta Jag startade flera MySQL-noder med en verklig belastning (Sysbench TPC-C Test), som var och en emulerade 10 noder. Linux/MySQL.
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 . 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.

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

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.

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.

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

CPU-belastningsspikar

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.

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.


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.


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.

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

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

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
