TSDB elemzés a Prometheus 2-ben

TSDB elemzés a Prometheus 2-ben

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: StackScript. A legreálisabb terhelés létrehozásához használja ezt StackScript Elindítottam több MySQL csomópontot valós terheléssel (Sysbench TPC-C Test), amelyek mindegyike 10 Linux/MySQL csomópontot emulált.
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 memóriakorlát. Ha nem elég kezelni a terhelést, akkor nagy késéseket fog tapasztalni, és egyes kérések meghiúsulnak. A memóriahasználat a Prometheus 2-ben kulccsal konfigurálható 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.

TSDB elemzés a Prometheus 2-ben

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 Irányítópult. PMM-hez tervezték, de kisebb módosításokkal minden Prometheus telepítéshez illeszkedik.
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.

TSDB elemzés a Prometheus 2-ben

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.

TSDB elemzés a Prometheus 2-ben

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

TSDB elemzés a Prometheus 2-ben

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

TSDB elemzés a Prometheus 2-ben

CPU terhelési csúcsok

TSDB elemzés a Prometheus 2-ben

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.

TSDB elemzés a Prometheus 2-ben

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.

TSDB elemzés a Prometheus 2-ben

TSDB elemzés a Prometheus 2-ben

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.

TSDB elemzés a Prometheus 2-ben

TSDB elemzés a Prometheus 2-ben

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.

TSDB elemzés a Prometheus 2-ben

Azt is észreveheti, hogy a Prometheus exportőr egy másodpercre leáll.

TSDB elemzés a Prometheus 2-ben

Összefüggéseket észlelhetünk a szemétszállítással (GC).

TSDB elemzés a Prometheus 2-ben

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

Hozzászólás