A Prometheus 2 idősoros adatbázisa (TSDB) kiváló példa egy olyan mérnöki megoldásra, amely jelentős fejlesztéseket kínál a Prometheus 2 v1-es tárolójához képest az adatgyűjtési sebesség, a lekérdezések végrehajtása és az erőforrás-hatékonyság tekintetében. A Prometheus 2-t a Percona Monitoring and Management (PMM) programban valósítottuk meg, és lehetőségem volt megérteni a Prometheus 2 TSDB teljesítményét. Ebben a cikkben ezeknek a megfigyeléseknek az eredményeiről fogok beszélni.
Átlagos Prometheus munkaterhelés
Azok számára, akik hozzászoktak az általános célú adatbázisok kezeléséhez, a tipikus Prometheus munkaterhelés meglehetősen érdekes. Az adatgyűjtési sebesség általában stabil: általában az Ön által felügyelt szolgáltatások megközelítőleg ugyanannyi mérőszámot küldenek, és az infrastruktúra viszonylag lassan változik.
Az információkérések különböző forrásokból származhatnak. Ezek egy része, például a riasztások is stabil és kiszámítható értékre törekednek. Mások, például a felhasználói kérések sorozatfelvételeket okozhatnak, bár ez a legtöbb munkaterhelésnél nem így van.
Terhelési teszt
A tesztelés során az adathalmozási képességre helyeztem a hangsúlyt. A Go 2.3.2-gyel összeállított Prometheus 1.10.1-t (a PMM 1.14 részeként) telepítettem a Linode szolgáltatásra a következő parancsfájl használatával:
A következő tesztek mindegyikét egy nyolc virtuális maggal és 32 GB memóriával rendelkező Linode szerveren végezték el, amelyen 20 terhelési szimuláció futott, kétszáz MySQL-példányt figyelve. Vagy Prometheus kifejezéssel 800 célpont, 440 kaparás másodpercenként, 380 ezer rekord másodpercenként és 1,7 millió aktív idősor.
Tervezés
A hagyományos adatbázisok, köztük a Prometheus 1.x által használt, szokásos megközelítése az, hogy storage.tsdb.min-block-duration
, amely meghatározza, hogy mennyi ideig tárolják a felvételeket a memóriában, mielőtt a lemezre öblítenék (alapértelmezett 2 óra). A szükséges memória mennyisége a nettó bejövő adatfolyamhoz hozzáadott idősorok, címkék és kaparók számától függ. A lemezterületet tekintve a Prometheus rekordonként (mintánként) 3 bájtot kíván használni. Másrészt a memóriaigény sokkal magasabb.
Bár lehetséges a blokkméret konfigurálása, nem ajánlott manuálisan konfigurálni, így kénytelen annyi memóriát adni a Prometheusnak, amennyi a munkaterheléséhez szükséges.
Ha nincs elég memória a bejövő metrikafolyam támogatásához, a Prometheus kiesik a memóriából, vagy az OOM gyilkos hozzájut.
A swap hozzáadása az összeomlás késleltetésére, amikor a Prometheus memóriája kifogy, nem igazán segít, mert ennek a funkciónak a használata robbanásszerű memóriafelhasználást okoz. Szerintem valami köze van a Go-hoz, a szemétgyűjtőjéhez és a cseréhez.
Egy másik érdekes megközelítés az, hogy a fejblokkot úgy konfigurálják, hogy egy bizonyos időpontban a lemezre öblítsék, ahelyett, hogy a folyamat kezdetétől számítanák.
Amint az a grafikonon látható, a lemezre történő öblítés kétóránként történik. Ha a min-block-duration paramétert egy órára módosítja, akkor ezek az alaphelyzetbe állítások fél óra elteltével minden órán megtörténnek.
Ha ezt és más grafikonokat szeretné használni a Prometheus telepítésében, akkor ezt használhatja
Van egy aktív blokk, az úgynevezett fejblokk, amely a memóriában van tárolva; a régebbi adatokkal rendelkező blokkok a következőn keresztül érhetők el mmap()
. Ez kiküszöböli a gyorsítótár külön konfigurálását, de azt is jelenti, hogy elegendő helyet kell hagyni az operációs rendszer gyorsítótárának, ha régebbi adatokat szeretne lekérdezni, mint amit a fejblokk képes befogadni.
Ez azt is jelenti, hogy a Prometheus virtuális memóriafogyasztása meglehetősen magasnak tűnik, ami miatt nem kell aggódni.
Egy másik érdekes tervezési pont a WAL (write ahead log) használata. Amint az a tárolási dokumentációból látható, a Prometheus WAL-t használ az összeomlások elkerülésére. Az adatok túlélhetőségét garantáló konkrét mechanizmusok sajnos nem jól dokumentáltak. A Prometheus 2.3.2-es verziója 10 másodpercenként öblíti a WAL-t a lemezre, és ez a beállítás a felhasználó által nem konfigurálható.
Tömörítések
A Prometheus TSDB-t úgy tervezték, mint egy LSM (Log Structured Merge) tárolót: a fejblokkot rendszeres időközönként a lemezre öblítik, míg a tömörítő mechanizmus több blokkot kombinál, hogy elkerülje a túl sok blokk vizsgálatát a lekérdezések során. Itt láthatja a blokkok számát, amit a tesztrendszeren megfigyeltem egy napi betöltés után.
Ha többet szeretne megtudni az áruházról, akkor megvizsgálhatja a meta.json fájlt, amely információkat tartalmaz az elérhető blokkokról és azok létrejöttéről.
{
"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
}
A Prometheusban a tömörítések ahhoz az időponthoz vannak kötve, amikor a fejblokkot a lemezre öblítik. Ezen a ponton több ilyen művelet is elvégezhető.
Úgy tűnik, hogy a tömörítések semmilyen módon nem korlátozottak, és nagy I/O-csúcsokat okozhatnak a lemezen a végrehajtás során.
CPU terhelési csúcsok
Természetesen ez meglehetősen negatív hatással van a rendszer sebességére, és komoly kihívás elé állítja az LSM-tárolást is: hogyan lehet tömöríteni a magas kérési arányokat anélkül, hogy túl sok többletköltséget okozna?
A memória használata a tömörítési folyamatban is elég érdekesnek tűnik.
Láthatjuk, hogy tömörítés után a memória nagy része hogyan változtatja át az állapotát Cached-ről szabadra: ez azt jelenti, hogy a potenciálisan értékes információkat eltávolították onnan. Érdekelne, hogy itt használják-e fadvice()
vagy valami más minimalizálási technika, vagy azért, mert a gyorsítótár felszabadult a tömörítés során megsemmisült blokkoktól?
Felépülés kudarc után
A kudarcokból való felépülés időbe telik, és ennek jó oka van. Egy millió rekord/másodperc bejövő adatfolyam esetén körülbelül 25 percet kellett várnom, amíg a helyreállítás az SSD-meghajtó figyelembevételével megtörtént.
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."
A helyreállítási folyamat fő problémája a magas memóriafogyasztás. Annak ellenére, hogy normál helyzetben a szerver stabilan tud működni ugyanannyi memóriával, ha összeomlik, előfordulhat, hogy az OOM miatt nem áll helyre. Az egyetlen megoldást az volt, hogy letiltottam az adatgyűjtést, előhívtam a szervert, hagytam helyreállni és újraindítottam az adatgyűjtés engedélyezésével.
Bemelegítés
Egy másik viselkedés, amelyet szem előtt kell tartani a bemelegítés során, az alacsony teljesítmény és a magas erőforrás-fogyasztás közötti kapcsolat közvetlenül az indítás után. Néhány, de nem minden indítás során komoly terhelést figyeltem meg a CPU-n és a memórián.
A memóriahasználat hiányosságai azt jelzik, hogy a Prometheus nem tudja kezdettől fogva konfigurálni az összes gyűjteményt, és bizonyos információk elvesznek.
Nem jöttem rá a magas CPU és memória terhelés pontos okára. Gyanítom, hogy ez annak köszönhető, hogy a fejblokkban nagy frekvenciával új idősorokat hoztak létre.
CPU terhelési hullámok
A meglehetősen nagy I/O terhelést okozó tömörítések mellett kétpercenként komoly kiugrásokat tapasztaltam a CPU terhelésben. A kitörések hosszabbak, ha nagy a bemeneti áramlás, és úgy tűnik, hogy a Go szemétgyűjtője okozza őket, és legalább néhány mag teljesen meg van terhelve.
Ezek az ugrások nem is olyan jelentéktelenek. Úgy tűnik, hogy amikor ezek előfordulnak, a Prometheus belső belépési pontja és mérőszámai elérhetetlenné válnak, ami adathiányokat okoz ugyanabban az időszakban.
Azt is észreveheti, hogy a Prometheus exportőr egy másodpercre leáll.
Összefüggéseket észlelhetünk a szemétszállítással (GC).
Következtetés
A Prometheus 2 TSDB-je gyors, több millió idősort és egyben több ezer rekordot képes kezelni másodpercenként, meglehetősen szerény hardver használatával. A CPU és a lemez I/O kihasználtsága is lenyűgöző. Példám másodpercenként akár 200 000 mérőszámot mutatott magonként.
A bővítés megtervezéséhez elegendő mennyiségű memóriára kell emlékeznie, és ennek valódi memóriának kell lennie. A felhasznált memória mennyisége, amelyet megfigyeltem, körülbelül 5 GB volt a bejövő adatfolyam 100 000 rekordjaként másodpercenként, ami az operációs rendszer gyorsítótárával együtt körülbelül 8 GB foglalt memóriát adott.
Természetesen még sokat kell dolgozni a CPU és a lemez I/O tüskék megszelídítésén, és ez nem meglepő, ha figyelembe vesszük, hogy a fiatal TSDB Prometheus 2 mennyire hasonlít az InnoDB-hez, TokuDB-hez, RocksDB-hez, WiredTigerhez, de mindegyiknek hasonló volt problémák az életciklusuk elején.
Forrás: will.com