Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Soovitan teil lugeda Alexander Valyalkini 2019. aasta lõpu aruande „Optimeerimine VictoriaMetricsis” ärakirja.

VictoriaMetrics — kiire ja skaleeritav DBMS andmete salvestamiseks ja töötlemiseks aegridade kujul (kirje moodustab aja ja sellele ajale vastava väärtuste komplekti, mis saadakse näiteks andurite oleku perioodilise küsitluse või andmete kogumise teel mõõdikud).

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Siin on link selle raporti videole - https://youtu.be/MZ5P21j_HLE

Slaidid

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Räägi meile endast. Mina olen Aleksander Valjalkin. Siin minu GitHubi konto. Olen kirglik Go ja jõudluse optimeerimise vastu. Kirjutasin palju kasulikke ja mitte eriti kasulikke teeke. Nad algavad kummastki fastvõi koos quick eesliide.

Praegu töötan VictoriaMetricsi kallal. Mis see on ja mida ma seal teen? Ma räägin sellest selles esitluses.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Aruande ülevaade on järgmine:

  • Esiteks räägin teile, mis on VictoriaMetrics.
  • Siis ma ütlen teile, mis aegread on.
  • Seejärel räägin teile, kuidas aegridade andmebaas töötab.
  • Järgmisena räägin teile andmebaasi arhitektuurist: millest see koosneb.
  • Ja siis liigume edasi VictoriaMetricsi optimeerimiste juurde. See on ümberpööratud indeksi optimeerimine ja Go bitikomplekti rakendamise optimeerimine.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Kas keegi publikust teab, mis on VictoriaMetrics? Vau, paljud inimesed juba teavad. See on hea uudis. Kes veel ei tea, siis see on aegridade andmebaas. See põhineb ClickHouse'i arhitektuuril, mõnel ClickHouse'i rakendamise üksikasjal. Näiteks: MergeTree, paralleelarvutus kõigi saadaolevate protsessorituumade kohta ja jõudluse optimeerimine protsessori vahemällu paigutatud andmeplokkidega töötades.

VictoriaMetrics pakub paremat andmete tihendamist kui teised aegridade andmebaasid.

See mastaabib vertikaalselt - see tähendab, et saate ühes arvutis lisada rohkem protsessoreid, rohkem RAM-i. VictoriaMetrics kasutab neid olemasolevaid ressursse edukalt ja parandab lineaarset tootlikkust.

VictoriaMetrics skaleerib ka horisontaalselt – see tähendab, et saate VictoriaMetricsi klastrisse lisada täiendavaid sõlme ja selle jõudlus suureneb peaaegu lineaarselt.

Nagu arvasite, on VictoriaMetrics kiire andmebaas, sest ma ei saa teisi kirjutada. Ja see on kirjas Go, nii et ma räägin sellest sellel kohtumisel.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Kes teab, mis on aegrida? Ta tunneb ka paljusid inimesi. Aegrida on paaride jada (timestamp, значение), kus need paarid on sorteeritud aja järgi. Väärtus on ujukomaarv – float64.

Iga aegrida on üheselt identifitseeritud võtmega. Millest see võti koosneb? See koosneb võtme-väärtuste paaride mittetühjast komplektist.

Siin on näide aegreast. Selle seeria võti on paaride loend: __name__="cpu_usage" on mõõdiku nimi, instance="my-server" - see on arvuti, kuhu see mõõdik kogutakse, datacenter="us-east" - see on andmekeskus, kus see arvuti asub.

Saime aegrea nime, mis koosnes kolmest võtme-väärtuse paarist. See võti vastab paaride loendile (timestamp, value). t1, t3, t3, ..., tN - need on ajatemplid, 10, 20, 12, ..., 15 — vastavad väärtused. See on antud rea protsessori kasutus teatud ajahetkel.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Kus saab aegridu kasutada? Kas kellelgi on aimu?

  • DevOpsis saate mõõta protsessorit, RAM-i, võrku, rps-i, vigade arvu jne.
  • IoT – saame mõõta temperatuuri, rõhku, geokoordinaate ja midagi muud.
  • Samuti finantseerimine – saame jälgida kõikvõimalike aktsiate ja valuutade hindu.
  • Lisaks saab aegridu kasutada tootmisprotsesside jälgimisel tehastes. Meil on kasutajaid, kes kasutavad VictoriaMetricsi tuuleturbiinide jälgimiseks robotite jaoks.
  • Aegridad on kasulikud ka erinevate seadmete anduritelt info kogumisel. Näiteks mootori jaoks; rehvirõhu mõõtmiseks; kiiruse, vahemaa mõõtmiseks; bensiinikulu mõõtmiseks jne.
  • Aegridu saab kasutada ka lennukite jälgimiseks. Igal lennukil on must kast, mis kogub aegridu lennuki tervise erinevate parameetrite kohta. Aegridu kasutatakse ka kosmosetööstuses.
  • Tervishoid on vererõhk, pulss jne.

Võib-olla on rohkem rakendusi, mille ma unustasin, kuid loodan, et saate aru, et aegridu kasutatakse tänapäeva maailmas aktiivselt. Ja nende kasutusmaht kasvab iga aastaga.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Miks vajate aegridade andmebaasi? Miks ei saa aegridade salvestamiseks kasutada tavalist relatsiooniandmebaasi?

Kuna aegread sisaldavad tavaliselt suurel hulgal informatsiooni, mida tavapärastes andmebaasides on raske salvestada ja töödelda. Seetõttu ilmusid aegridade jaoks spetsiaalsed andmebaasid. Need alused salvestavad tõhusalt punkte (timestamp, value) antud võtmega. Need pakuvad API-d salvestatud andmete lugemiseks võtme, ühe võtme-väärtuse paari või mitme võtme-väärtuse paari või regexpi järgi. Näiteks kui soovite leida Ameerikas asuvas andmekeskuses kõigi oma teenuste CPU koormust, siis peate kasutama seda pseudopäringut.

Tavaliselt pakuvad aegridade andmebaasid spetsiaalseid päringukeeli, kuna aegridade SQL ei sobi eriti hästi. Kuigi on andmebaase, mis toetavad SQL-i, pole see eriti sobiv. Päringukeeled nagu PromQL, InfluxQL, Vool, Q. Loodan, et keegi on vähemalt ühte neist keeltest kuulnud. Paljud inimesed on ilmselt PromQL-ist kuulnud. See on Prometheuse päringukeel.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Selline näeb välja kaasaegne aegridade andmebaasi arhitektuur, kasutades näitena VictoriaMetricsi.

See koosneb kahest osast. See on ümberpööratud indeksi ja aegridade väärtuste salvestamine. Need hoidlad on eraldatud.

Kui andmebaasi saabub uus kirje, pääseme esmalt juurde pöördindeksile, et leida antud komplekti aegrea identifikaator label=value antud mõõdiku jaoks. Leiame selle identifikaatori ja salvestame väärtuse andmesalves.

Kui tuleb taotlus TSDB-st andmete toomiseks, läheme esmalt ümberpööratud indeksisse. Võtame kõik timeseries_ids rekordid, mis sellele komplektile vastavad label=value. Ja siis saame andmelaost kõik vajalikud andmed, mida indekseerib timeseries_ids.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Vaatame näidet, kuidas aegridade andmebaas töötleb sissetulevat valikupäringut.

  • Esiteks saab ta kõik timeseries_ids inverteeritud indeksist, mis sisaldab antud paare label=value, või rahuldada etteantud regulaaravaldis.
  • Seejärel hangib see leitud punktide jaoks välja kõik andmepunktid andmesalvestusest teatud ajaintervalli järel timeseries_ids.
  • Pärast seda teeb andmebaas vastavalt kasutaja soovile nende andmepunktide kohta mõned arvutused. Ja pärast seda tagastab see vastuse.

Selles esitluses räägin teile esimesest osast. See on otsing timeseries_ids ümberpööratud indeksi järgi. Teist ja kolmandat osa saate vaadata hiljem VictoriaMetricsi allikadvõi oodake, kuni muud aruanded koostan :)

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Liigume edasi pöördindeksi juurde. Paljud võivad arvata, et see on lihtne. Kes teab, mis on pööratud indeks ja kuidas see töötab? Oh, inimesi pole enam nii palju. Proovime aru saada, mis see on.

See on tegelikult lihtne. See on lihtsalt sõnastik, mis kaardistab võtme väärtusele. Mis on võti? See paar label=valueKus label и value - need on jooned. Ja väärtused on komplekt timeseries_ids, mis sisaldab antud paari label=value.

Pööratud indeks võimaldab teil kiiresti kõike leida timeseries_ids, mis on andnud label=value.

Samuti võimaldab see kiiresti leida timeseries_ids aegridad mitmele paarile label=valuevõi paaridele label=regexp. Kuidas see juhtub? Leides hulga ristumiskoha timeseries_ids iga paari jaoks label=value.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Vaatame ümberpööratud indeksi erinevaid rakendusi. Alustame kõige lihtsamast naiivsest teostusest. Ta näeb välja selline.

Funktsioon getMetricIDs saab stringide nimekirja. Iga rida sisaldab label=value. See funktsioon tagastab loendi metricIDs.

Kuidas see töötab? Siin on globaalne muutuja nimega invertedIndex. See on tavaline sõnastik (map), mis vastendab stringi sisenditeks viiludeks. Rida sisaldab label=value.

Funktsiooni rakendamine: hanki metricIDs esimese jaoks label=value, siis läbime kõik muu label=value, saame aru metricIDs neile. Ja helistage funktsioonile intersectInts, mida arutatakse allpool. Ja see funktsioon tagastab nende loendite ristumiskoha.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Nagu näete, pole ümberpööratud indeksi rakendamine kuigi keeruline. Kuid see on naiivne teostus. Millised puudused sellel on? Naiivse teostuse peamine puudus on see, et selline ümberpööratud indeks salvestatakse RAM-i. Pärast rakenduse taaskäivitamist kaotame selle indeksi. Seda indeksit kettale ei salvestata. Selline ümberpööratud indeks tõenäoliselt andmebaasi ei sobi.

Teine puudus on samuti seotud mäluga. Pööratud indeks peab mahtuma RAM-i. Kui see ületab RAM-i suuruse, siis ilmselgelt saame - mälu veast välja. Ja programm ei tööta.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Seda probleemi saab lahendada valmislahenduste abil, näiteks TaseDBVõi RocksDB.

Lühidalt, me vajame andmebaasi, mis võimaldab kiiresti teha kolm toimingut.

  • Esimene toiming on salvestamine ключ-значение sellesse andmebaasi. Ta teeb seda väga kiiresti, kus ключ-значение on suvalised stringid.
  • Teine toiming on väärtuse kiire otsimine antud võtme abil.
  • Ja kolmas toiming on kõigi väärtuste kiire otsimine antud prefiksi järgi.

LevelDB ja RocksDB – need andmebaasid töötasid välja Google ja Facebook. Kõigepealt tuli LevelDB. Siis võtsid Facebooki poisid LevelDB ja hakkasid seda täiustama, tegid RocksDB. Nüüd töötavad peaaegu kõik sisemised andmebaasid Facebookis RocksDB-s, sealhulgas need, mis on üle viidud RocksDB-sse ja MySQL-i. Nad andsid talle nime MyRocks.

Inverteeritud indeksit saab rakendada LevelDB abil. Kuidas seda teha? Salvestame võtmena label=value. Ja väärtus on selle aegrea identifikaator, kus paar esineb label=value.

Kui meil on antud paariga palju aegridu label=value, siis on selles andmebaasis palju sama võtmega ja erineva võtmega ridu timeseries_ids. Kõigi nimekirja saamiseks timeseries_ids, mis algavad sellega label=prefix, teeme vahemiku skannimise, mille jaoks see andmebaas on optimeeritud. See tähendab, et valime kõik read, mis algavad label=prefix ja hankige vajalik timeseries_ids.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Siin on näide selle kohta, kuidas see Go-s välja näeks. Meil on tagurpidi indeks. See on LevelDB.

Funktsioon on sama, mis naiivsel teostusel. See kordab naiivset teostust peaaegu rida-realt. Ainus asi on selles, et selle asemel, et pöörduda map pääseme juurde pööratud indeksile. Saame kõik väärtused esimeseks label=value. Seejärel käime läbi kõik ülejäänud paarid label=value ja hankige neile vastavad mõõdikute ID-d. Siis leiame ristmiku.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Tundub, et kõik on korras, kuid sellel lahendusel on puudusi. VictoriaMetrics rakendas algselt LevelDB-l põhineva ümberpööratud indeksi. Kuid lõpuks pidin sellest loobuma.

Miks? Kuna LevelDB on aeglasem kui naiivne rakendamine. Naiivses teostuses, kui antud võti on antud, hangime kohe kogu lõigu metricIDs. See on väga kiire toiming – kogu viil on kasutamiseks valmis.

LevelDB-s iga kord, kui funktsiooni kutsutakse GetValues peate läbima kõik read, mis algavad label=value. Ja hankige iga rea ​​väärtus timeseries_ids. Sellistest timeseries_ids koguge neist tükk timeseries_ids. Ilmselgelt on see palju aeglasem kui lihtsalt tavalisele kaardile võtmega juurdepääs.

Teine puudus on see, et LevelDB on kirjutatud C-keeles. C-funktsioonide väljakutsumine Go-st ei ole väga kiire. See võtab sadu nanosekundeid. See pole väga kiire, sest võrreldes go-s kirjutatud tavalise funktsioonikutsega, mis võtab aega 1-5 nanosekundit, on jõudluse vahe kümneid kordi. VictoriaMetricsi jaoks oli see saatuslik viga :)

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Nii et ma kirjutasin enda ümberpööratud indeksi teostuse. Ja ta kutsus teda mergeset.

Mergeset põhineb MergeTree andmestruktuuril. See andmestruktuur on laenatud ClickHouse'ilt. Ilmselgelt tuleks mergeset kiireks otsimiseks optimeerida timeseries_ids vastavalt antud võtmele. Mergeset on kirjutatud täielikult Go keeles. Sa näed VictoriaMetricsi allikad GitHubis. Mergeseti rakendamine on kaustas /lib/mergeset. Võite proovida aru saada, mis seal toimub.

Mergeset API on väga sarnane LevelDB ja RocksDB-ga. See tähendab, et see võimaldab teil kiiresti uusi kirjeid sinna salvestada ja kiiresti kirjeid etteantud eesliite järgi valida.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Mergeseti puudustest räägime hiljem. Nüüd räägime sellest, millised probleemid tekkisid VictoriaMetricsiga tootmises pöördindeksi rakendamisel.

Miks need tekkisid?

Esimene põhjus on suur väljalangemise määr. Vene keelde tõlgituna on see aegridade sagedane muutus. See on siis, kui aegrida lõpeb ja algab uus seeria või algab palju uusi aegridu. Ja seda juhtub sageli.

Teine põhjus on aegridade suur arv. Alguses, kui seire kogus populaarsust, oli aegridade arv väike. Näiteks peate iga arvuti jaoks jälgima protsessori, mälu, võrgu ja ketta koormust. 4 aegrida arvuti kohta. Oletame, et teil on 100 arvutit ja 400 aegrida. Seda on väga vähe.

Aja jooksul said inimesed aru, et nad saavad mõõta üksikasjalikumat teavet. Näiteks mõõtke mitte kogu protsessori koormust, vaid iga protsessori tuuma eraldi. Kui teil on 40 protsessorituuma, on teil protsessori koormuse mõõtmiseks 40 korda rohkem aegridu.

Kuid see pole veel kõik. Igal protsessori tuumal võib jõudeoleku ajal olla mitu olekut, näiteks jõudeolek. Ja ka töötada kasutajaruumis, töötada tuumaruumis ja muudes olekutes. Ja iga sellist olekut saab mõõta ka eraldi aegreana. See suurendab lisaks ridade arvu 7-8 korda.

Ühest mõõdikust saime ainult ühe arvuti kohta 40 x 8 = 320 mõõdikut. Korrutades 100-ga, saame 32 asemel 000 400.

Siis tuli Kubernetes. Ja see läks hullemaks, kuna Kubernetes saab majutada paljusid erinevaid teenuseid. Iga Kubernetese teenus koosneb paljudest kaustadest. Ja seda kõike tuleb jälgida. Lisaks juurutame pidevalt teie teenuste uusi versioone. Iga uue versiooni jaoks tuleb luua uus aegrida. Selle tulemusena kasvab aegridade arv plahvatuslikult ja oleme silmitsi suure hulga aegridade probleemiga, mida nimetatakse kõrge kardinaalsuseks. VictoriaMetrics tuleb sellega võrreldes teiste aegridade andmebaasidega edukalt toime.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Vaatame lähemalt kõrget loobumismäära. Mis põhjustab tootmise kõrget katkestamise määra? Sest mõned siltide ja siltide tähendused muutuvad pidevalt.

Võtke näiteks Kubernetes, millel on kontseptsioon deployment, st kui teie rakenduse uus versioon avaldatakse. Mingil põhjusel otsustasid Kubernetese arendajad lisada sildile juurutamise ID.

Milleni see viis? Lisaks katkevad iga uue kasutuselevõtuga kõik vanad aegread ja nende asemel algavad uued aegread uue sildi väärtusega deployment_id. Selliseid ridu võib olla sadu tuhandeid ja isegi miljoneid.

Kõige selle juures on oluline see, et aegridade koguarv kasvab, kuid hetkel aktiivsete ja andmeid vastuvõtvate aegridade arv jääb muutumatuks. Seda olekut nimetatakse kõrgeks churn rate’iks.

Kõrge loobumissageduse peamine probleem on tagada kõigi aegridade jaoks konstantne otsimiskiirus teatud sildikomplekti jaoks teatud ajavahemiku jooksul. Tavaliselt on see viimase tunni või päeva ajavahemik.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Kuidas seda probleemi lahendada? Siin on esimene variant. Selle eesmärk on jagada ümberpööratud indeks aja jooksul sõltumatuteks osadeks. See tähendab, et mõni ajavahemik möödub, lõpetame töö praeguse inverteeritud indeksiga. Ja looge uus ümberpööratud indeks. Möödub järjekordne ajaintervall, loome teise ja teise.

Ja nendest ümberpööratud indeksitest valimi võttes leiame pöördindeksite komplekti, mis jäävad antud intervalli. Ja vastavalt sellele valime sealt aegrea id.

See säästab ressursse, sest me ei pea vaatama osi, mis ei jää antud intervallisse. See tähendab, et kui valime tavaliselt viimase tunni andmed, siis eelmiste ajavahemike puhul jätame päringud vahele.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Selle probleemi lahendamiseks on veel üks võimalus. Selle eesmärk on salvestada iga päeva jaoks eraldi loend sellel päeval toimunud aegridade ID-dest.

Selle lahenduse eeliseks eelmise lahenduse ees on see, et me ei dubleeri aegridade infot, mis aja jooksul ei kao. Nad on pidevalt kohal ega muutu.

Puuduseks on see, et sellist lahendust on keerulisem rakendada ja raskem siluda. Ja VictoriaMetrics valis selle lahenduse. Nii see ajalooliselt juhtus. See lahendus toimib hästi ka võrreldes eelmisega. Kuna seda lahendust ei rakendatud, kuna igas partitsioonis on vaja dubleerida andmeid aegridade jaoks, mis ei muutu, st mis aja jooksul ei kao. VictoriaMetrics oli peamiselt optimeeritud kettaruumi tarbimiseks ja eelmine rakendus muutis kettaruumi tarbimise hullemaks. Kuid see teostus sobib paremini kettaruumi tarbimise minimeerimiseks, nii et see valiti.

Ma pidin temaga võitlema. Võitlus seisnes selles, et selles teostuses peate ikkagi valima palju suurema numbri timeseries_ids andmete jaoks kui siis, kui pöördindeks on ajaliselt jaotatud.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Kuidas me selle probleemi lahendasime? Lahendasime selle originaalsel viisil – salvestades igasse ümberpööratud indeksikirjesse ühe identifikaatori asemel mitu aegrea identifikaatorit. See tähendab, et meil on võti label=value, mis esineb igas aegreas. Ja nüüd salvestame mitu timeseries_ids ühes sissekandes.

Siin on näide. Varem oli meil N kirjet, kuid nüüd on meil üks kirje, mille eesliide on sama, mis kõigil teistel. Eelmise kirje puhul sisaldab väärtus kõiki aegridade ID-sid.

See võimaldas sellise ümberpööratud indeksi skaneerimiskiirust suurendada kuni 10 korda. Ja see võimaldas meil vähendada vahemälu mälutarbimist, sest nüüd salvestame stringi label=value ainult üks kord vahemälus koos N korda. Ja see rida võib olla suur, kui salvestate oma siltidesse ja siltidesse pikki ridu, mida Kubernetesele meeldib sinna lükata.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Teine võimalus pööratud indeksis otsimise kiirendamiseks on sharding. Mitme ümberpööratud indeksi loomine ühe asemel ja andmete jagamine nende vahel võtmega. See on komplekt key=value aur. See tähendab, et saame mitu sõltumatut ümberpööratud indeksit, mida saame päringuid teha paralleelselt mitmel protsessoril. Varasemad teostused lubasid töötada ainult ühe protsessori režiimis, st andmete skannimist ainult ühes tuumas. See lahendus võimaldab skannida andmeid korraga mitmel tuumal, nagu ClickHouse’ile meeldib. Seda plaanime ellu viia.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Nüüd pöördume tagasi oma lammaste juurde – ristumisfunktsiooni juurde timeseries_ids. Mõelgem, millised rakendused võivad olla. See funktsioon võimaldab teil leida timeseries_ids antud komplekti jaoks label=value.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Esimene võimalus on naiivne teostus. Kaks pesastatud silmust. Siit saame funktsiooni sisendi intersectInts kaks viilu - a и b. Väljundis peaks see meile tagastama nende viilude ristumiskoha.

Naiivne teostus näeb välja selline. Kordame üle kõik lõigu väärtused a, selle tsükli sees käime läbi kõik lõigu väärtused b. Ja me võrdleme neid. Kui need klapivad, siis oleme ristmiku leidnud. Ja salvestage see sisse result.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Millised on puudused? Ruutiline keerukus on selle peamine puudus. Näiteks kui teie mõõtmed on viil a и b miljon korraga, siis see funktsioon ei anna teile kunagi vastust. Sest see peab tegema triljonit iteratsiooni, mis on isegi tänapäevaste arvutite jaoks palju.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Teine teostus põhineb kaardil. Koostame kaardi. Panime sellele kaardile kõik lõigu väärtused a. Seejärel läbime viilu eraldi silmuses b. Ja me kontrollime, kas see väärtus pärineb viilust b kaardil. Kui see on olemas, lisage see tulemusele.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Mis kasu sellest on? Eeliseks on see, et on ainult lineaarne keerukus. See tähendab, et funktsioon käivitub suuremate viilude puhul palju kiiremini. Miljoni suuruse lõigu puhul täidetakse seda funktsiooni 2 miljoni iteratsiooniga, erinevalt eelmise funktsiooni triljonist iteratsioonist.

Negatiivne külg on see, et see funktsioon nõuab selle kaardi loomiseks rohkem mälu.

Teiseks puuduseks on räsimise suured üldkulud. See puudus pole eriti ilmne. Ja meie jaoks polnud see ka eriti ilmne, nii et algul toimus VictoriaMetricsis ristmiku rakendamine kaardi kaudu. Siis aga näitas profileerimine, et põhiprotsessori aeg kulub kaardile kirjutamisele ja selle kaardi väärtuse olemasolu kontrollimisele.

Miks raisatakse nendes kohtades CPU aega? Kuna Go teostab nendel ridadel räsioperatsiooni. See tähendab, et see arvutab võtme räsi, et pääseda sellele HashMapi antud indeksis juurde. Räsi arvutamise toiming viiakse lõpule kümnete nanosekundite jooksul. VictoriaMetricsi jaoks on see aeglane.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Otsustasin rakendada spetsiaalselt selle juhtumi jaoks optimeeritud bitikomplekti. Selline näeb nüüd välja kahe viilu ristumiskoht. Siin loome bitikomplekti. Lisame sellele elemendid esimesest viilust. Seejärel kontrollime nende elementide olemasolu teises viilus. Ja lisage need tulemusele. See tähendab, et see ei erine peaaegu eelmisest näitest. Ainus asi on see, et asendasime juurdepääsu kaardile kohandatud funktsioonidega add и has.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Esmapilgul tundub, et see peaks aeglasemalt toimima, kui varem oli seal kasutatud standardkaarti ja siis kutsutakse välja mingid muud funktsioonid, aga profileerimine näitab, et see asi töötab VictoriaMetricsi puhul 10 korda kiiremini kui tavakaart.

Lisaks kasutab see kaardi rakendamisega võrreldes palju vähem mälu. Sest me salvestame siia kaheksabaidiste väärtuste asemel bitte.

Selle teostuse puuduseks on see, et see pole nii ilmne, mitte triviaalne.

Teine puudus, mida paljud ei pruugi märgata, on see, et see rakendus ei pruugi mõnel juhul hästi toimida. See tähendab, et see on optimeeritud konkreetse juhtumi jaoks, selle VictoriaMetricsi aegridade ID-de ristumisjuhtumi jaoks. See ei tähenda, et see sobib kõikidel juhtudel. Kui seda kasutatakse valesti, ei saa me jõudluse kasvu, vaid mälu tühjenemise ja jõudluse aeglustumise.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Mõelgem selle struktuuri rakendamisele. Kui soovite vaadata, asub see VictoriaMetricsi allikates kaustas lib/uint64set. See on optimeeritud spetsiaalselt VictoriaMetricsi korpuse jaoks, kus timeseries_id on 64-bitine väärtus, kus esimesed 32 bitti on põhimõtteliselt konstantsed ja ainult viimased 32 bitti muutuvad.

Seda andmestruktuuri ei salvestata kettale, see töötab ainult mälus.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Siin on selle API. See ei ole väga keeruline. API on kohandatud konkreetselt VictoriaMetricsi kasutamise konkreetsele näitele. See tähendab, et siin pole tarbetuid funktsioone. Siin on funktsioonid, mida VictoriaMetrics selgesõnaliselt kasutab.

Funktsioonid on olemas add, mis lisab uusi väärtusi. Funktsioon on olemas has, mis kontrollib uusi väärtusi. Ja seal on funktsioon del, mis eemaldab väärtused. Seal on abifunktsioon len, mis tagastab komplekti suuruse. Funktsioon clone kloonid palju. Ja funktsioon appendto teisendab selle komplekti lõiguks timeseries_ids.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Selline näeb välja selle andmestruktuuri rakendamine. komplekt sisaldab kahte elementi:

  • ItemsCount on abiväli, mis võimaldab kiiresti tagastada komplekti elementide arvu. Saaks ka ilma selle abiväljata hakkama, aga see tuli siia lisada, sest VictoriaMetrics küsib sageli oma algoritmides bitsetile pikkust.

  • Teine väli on buckets. See on osa struktuurist bucket32. Iga struktuur salvestab hi valdkonnas. Need on ülemised 32 bitti. Ja kaks viilu - b16his и buckets kohta bucket16 struktuurid.

Siin on salvestatud 16-bitise struktuuri teise osa 64 ülemist bitti. Ja siin salvestatakse bitikomplektid iga baidi alumise 16 biti jaoks.

Bucket64 koosneb massiivist uint64. Pikkus arvutatakse nende konstantide abil. Ühes bucket16 maksimaalselt saab salvestada 2^16=65536 natuke. Kui jagate selle 8-ga, on see 8 kilobaiti. Kui jagate uuesti 8-ga, on see 1000 uint64 tähenduses. See on Bucket16 – see on meie 8-kilobaidine struktuur.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Vaatame, kuidas rakendatakse üht selle struktuuri meetodit uue väärtuse lisamiseks.

Kõik algab sellest uint64 tähendusi. Arvutame ülemised 32 bitti, arvutame alumise 32 bitti. Käime kõik läbi buckets. Võrdleme iga ämbri 32 parimat bitti lisatava väärtusega. Ja kui need ühtivad, kutsume funktsiooni add struktuuris b32 buckets. Ja lisage sinna alumised 32 bitti. Ja kui see tagasi tuleb true, siis see tähendab, et me lisasime sinna sellise väärtuse ja meil sellist väärtust ei olnud. Kui see naaseb false, siis oli selline tähendus juba olemas. Seejärel suurendame elementide arvu struktuuris.

Kui me ei leidnud seda, mida vajate bucket nõutava hi-väärtusega, siis kutsume funktsiooni välja addAlloc, mis toodab uue bucket, lisades selle kopa struktuuri.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

See on funktsiooni rakendamine b32.add. See sarnaneb eelmise rakendusega. Arvutame kõige olulisemad 16 bitti, kõige vähem olulised 16 bitti.

Seejärel läbime kõik ülemised 16 bitti. Leiame vasteid. Ja kui vaste on, kutsume lisamismeetodit, mida järgmisel lehel kaalume bucket16.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Ja siin on madalaim tase, mida tuleks võimalikult palju optimeerida. Arvutame eest uint64 id väärtus slice bitis ja ka bitmask. See on antud 64-bitise väärtuse mask, mida saab kasutada selle biti olemasolu kontrollimiseks või selle seadistamiseks. Kontrollime, kas see bitt on seatud, määrame selle ja tagastame kohaloleku. See on meie teostus, mis võimaldas meil kiirendada aegridade ristuvate ID-de tööd tavaliste kaartidega võrreldes 10 korda.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Lisaks sellele optimeerimisele on VictoriaMetricsil palju muid optimeerimisi. Enamik neist optimeerimistest lisati põhjusel, kuid pärast koodi tootmises profileerimist.

See on optimeerimise peamine reegel – ära lisa optimeerimist, eeldades, et siin on kitsaskoht, sest võib selguda, et kitsaskohta seal ei ole. Optimeerimine halvendab tavaliselt koodi kvaliteeti. Seetõttu tasub optimeerida alles pärast profileerimist ja soovitavalt tootmises, et tegemist oleks reaalsete andmetega. Kui kedagi huvitab, võib vaadata VictoriaMetricsi lähtekoodi ja uurida muid seal leiduvaid optimeerimisi.

Tehke VictoriaMetricsis optimeerimine. Aleksander Valalkin

Mul on küsimus bitseti kohta. Väga sarnane C++ vektori bool-rakendusega, optimeeritud bitikomplekt. Kas võtsid teostuse sealt?

Ei, mitte sealt. Selle bitikomplekti rakendamisel lähtusin teadmistest VictoriaMetricsis kasutatavate ID-aegridade struktuurist. Ja nende struktuur on selline, et ülemised 32 bitti on põhimõtteliselt konstantsed. Alumised 32 bitti võivad muutuda. Mida madalam on bitt, seda sagedamini võib see muutuda. Seetõttu on see rakendus spetsiaalselt selle andmestruktuuri jaoks optimeeritud. C++ teostus on minu teada optimeeritud üldjuhtumi jaoks. Kui optimeerite üldise juhtumi jaoks, tähendab see, et see ei ole konkreetse juhtumi jaoks kõige optimaalsem.

Samuti soovitan teil vaadata Aleksei Milovidi aruannet. Umbes kuu aega tagasi rääkis ta ClickHouse'is optimeerimisest konkreetsete erialade jaoks. Ta ütleb vaid, et üldiselt on C++ teostus või mõni muu teostus kohandatud haiglas keskmiselt hästi töötama. See võib toimida halvemini kui teadmistepõhine teostus, nagu meie oma, kus me teame, et 32 ​​parimat bitti on enamasti konstantsed.

Mul on teine ​​küsimus. Mis on põhimõtteline erinevus InfluxDB-st?

Põhimõttelisi erinevusi on palju. Jõudluse ja mälukulu osas näitab InfluxDB testides 10 korda rohkem mälukulu kõrge kardinaalsusega aegridade puhul, kui sul on neid palju, näiteks miljoneid. Näiteks VictoriaMetrics kulutab 1 GB miljoni aktiivse rea kohta, InfluxDB aga 10 GB. Ja see on suur erinevus.

Teine põhimõtteline erinevus on see, et InfluxDB-l on kummalised päringukeeled - Flux ja InfluxQL. Võrreldes aegridadega pole need eriti mugavad PromQL, mida toetab VictoriaMetrics. PromQL on Prometheuse päringukeel.

Ja veel üks erinevus on see, et InfluxDB-l on veidi kummaline andmemudel, kus igale reale saab salvestada mitu välja erineva siltide komplektiga. Need read on omakorda jagatud erinevateks tabeliteks. Need täiendavad komplikatsioonid raskendavad edasist tööd selle andmebaasiga. Seda on raske toetada ja mõista.

VictoriaMetricsis on kõik palju lihtsam. Seal on iga aegrida võtmeväärtus. Väärtus on punktide kogum - (timestamp, value), ja võti on komplekt label=value. Väljade ja mõõtmiste vahel ei ole vahet. See võimaldab teil valida mis tahes andmeid ja seejärel kombineerida, liita, lahutada, korrutada, jagada, erinevalt InfluxDB-st, kus erinevate ridade vahelisi arvutusi pole minu teada ikka veel rakendatud. Isegi kui need on rakendatud, on see keeruline, peate kirjutama palju koodi.

Mul on täpsustav küsimus. Kas ma sain õigesti aru, et seal on mingi probleem, millest sa rääkisid, et see ümberpööratud indeks ei mahu mällu, seega on seal partitsioonid?

Esiteks näitasin ümberpööratud indeksi naiivset rakendamist tavalisel Go kaardil. See teostus ei sobi andmebaaside jaoks, kuna seda ümberpööratud indeksit ei salvestata kettale ja andmebaas peab salvestama kettale, et need andmed jääksid taaskäivitamisel kättesaadavaks. Selle rakenduse korral kaob teie ümberpööratud indeks rakenduse taaskäivitamisel. Ja kaotate juurdepääsu kõikidele andmetele, kuna te ei leia neid.

Tere! Täname raporti eest! Minu nimi on Pavel. Olen pärit Wildberryst. Mul on teile paar küsimust. Küsimus üks. Kas arvate, et kui oleksite oma rakenduse arhitektuuri ülesehitamisel valinud teistsuguse põhimõtte ja jaotanud andmed aja jooksul, siis oleksite ehk saanud andmeid otsides ristuda, tuginedes ainult sellele, et üks partitsioon sisaldab andmeid ühe jaoks ajavahemik , st ühes ajavahemikus ja te ei peaks muretsema selle pärast, et teie tükid on erinevalt laiali? Küsimus number 2 - kuna rakendate sarnast algoritmi bitsetiga ja kõige muuga, siis võib-olla proovisite kasutada protsessori juhiseid? Võib-olla olete proovinud selliseid optimeerimisi?

Teisele vastan kohe. Me pole veel selleni jõudnud. Aga kui vaja, siis jõuame. Ja esimene, mis küsimus oli?

Arutasite kahte stsenaariumi. Ja nad ütlesid, et valisid teise keerulisema teostusega. Ja nad ei eelistanud esimest, kus andmed on aja järgi jaotatud.

Jah. Esimesel juhul oleks indeksi kogumaht suurem, sest igas partitsioonis peaksime salvestama dubleerivad andmed nende aegridade kohta, mis jätkuvad läbi kõigi nende partitsioonide. Ja kui teie aegridade churn rate on väike, st samu jadaid kasutatakse pidevalt, siis esimesel juhul kaotaksime hõivatud kettaruumis palju rohkem kui teisel juhul.

Ja nii – jah, aja jagamine on hea valik. Prometheus kasutab seda. Kuid Prometheusel on veel üks puudus. Nende andmete ühendamisel peab see säilitama kõigi siltide ja aegridade metateabe. Seega, kui sellega liidetavad andmetükid on suured, siis erinevalt VictoriaMetricsist suureneb liitmise ajal mälutarbimine väga palju. Ühendamisel ei tarbi VictoriaMetrics üldse mälu, kulub vaid paar kilobaiti, olenemata liidetavate andmetükkide suurusest.

Teie kasutatav algoritm kasutab mälu. See tähistab väärtusi sisaldavad ajaridade sildid. Ja nii kontrollite paaris olemasolu ühes ja teises andmemassiivis. Ja saate aru, kas ristumine toimus või mitte. Tavaliselt rakendavad andmebaasid kursoreid ja iteraatoreid, mis salvestavad nende praeguse sisu ja käitavad sorteeritud andmeid nende toimingute lihtsa keerukuse tõttu.

Miks me ei kasuta andmete läbimiseks kursoreid?

Jah.

Sorditud read salvestame LevelDB-sse või ühendamisse. Saame kursorit liigutada ja ristmiku leida. Miks me seda ei kasuta? Sest see on aeglane. Kuna kursorid tähendavad, et peate iga rea ​​jaoks funktsiooni kutsuma. Funktsioonikutse pikkus on 5 nanosekundit. Ja kui teil on 100 000 000 rida, siis selgub, et me kulutame pool sekundit lihtsalt funktsiooni kutsumisele.

Selline asi on jah. Ja minu viimane küsimus. Küsimus võib tunduda veidi kummaline. Miks ei ole võimalik andmete saabumise hetkel kõiki vajalikke agregaate lugeda ja neid vajalikul kujul salvestada? Miks säästa mõnes süsteemis, nagu VictoriaMetrics, ClickHouse jne, tohutuid mahtusid ja seejärel kulutada neile palju aega?

Toon näite, et asi selgem oleks. Ütleme, kuidas väike mänguasja spidomeeter töötab? See salvestab teie läbitud vahemaa, lisades selle kogu aeg ühele väärtusele ja teisel korral aja. Ja jagab. Ja saavutab keskmise kiiruse. Saate teha umbes sama asja. Lisage kõik vajalikud faktid käigu pealt kokku.

Olgu, ma saan küsimusest aru. Sinu eeskujul on oma koht. Kui teate, milliseid agregaate vajate, on see parim rakendus. Kuid probleem on selles, et inimesed salvestavad need mõõdikud, mõned andmed ClickHouse'i ja nad ei tea veel, kuidas nad neid tulevikus koondavad ja filtreerivad, seega peavad nad salvestama kõik algandmed. Aga kui teate, et peate midagi keskmiselt arvutama, siis miks mitte seda arvutada, selle asemel, et salvestada sinna hulk toorväärtusi? Kuid see on ainult siis, kui teate täpselt, mida vajate.

Muide, aegridade salvestamise andmebaasid toetavad agregaatide loendamist. Näiteks Prometheus toetab salvestamise reeglid. See tähendab, et seda saab teha, kui teate, milliseid üksusi vajate. VictoriaMetricsil seda veel pole, kuid tavaliselt eelneb sellele Prometheus, milles saab seda teha ümberkodeerimise reeglites.

Näiteks oma eelmises töökohas oli mul vaja lugeda libisevas aknas viimase tunni jooksul toimunud sündmuste arvu. Probleem on selles, et pidin Go-s tegema kohandatud teostuse, st selle asja loendamise teenuse. See teenus ei olnud lõppkokkuvõttes triviaalne, sest seda on raske arvutada. Rakendamine võib olla lihtne, kui peate loendama teatud ajavahemike järel mõningaid agregaate. Kui soovite libisevas aknas sündmusi loendada, pole see nii lihtne, kui tundub. Ma arvan, et seda pole ClickHouse'is ega ajaridade andmebaasides veel rakendatud, kuna seda on keeruline rakendada.

Ja veel üks küsimus. Rääkisime just keskmistamisest ja mulle meenus, et kunagi oli selline asi nagu Carbon taustaprogrammiga Graphite. Ja ta teadis, kuidas vanu andmeid harvendada, st jätta üks punkt minutis, üks punkt tunnis jne. Põhimõtteliselt on see üsna mugav, kui vajame toorandmeid suhteliselt kuu aega ja kõik muu saab hõreneda . Kuid Prometheus ja VictoriaMetrics seda funktsiooni ei toeta. Kas seda on plaanis toetada? Kui ei, siis miks mitte?

Täname küsimuse eest. Meie kasutajad küsivad seda küsimust perioodiliselt. Nad küsivad, millal lisame alladiskreetimise toe. Siin on mitmeid probleeme. Esiteks saab iga kasutaja aru downsampling midagi muud: keegi tahab saada suvalise punkti antud intervallil, keegi soovib maksimum-, miinimum-, keskmisi väärtusi. Kui paljud süsteemid kirjutavad andmeid teie andmebaasi, ei saa te seda kõike ühte liita. Võib juhtuda, et iga süsteem vajab erinevat hõrenemist. Ja seda on raske rakendada.

Ja teine ​​asi on see, et VictoriaMetrics, nagu ka ClickHouse, on optimeeritud suure hulga toorandmetega töötamiseks, nii et kui teie süsteemis on palju tuumasid, suudab see vähem kui sekundiga kühveldada miljard rida. Aegridade punktide skaneerimine VictoriaMetricsis – 50 000 000 punkti sekundis tuuma kohta. Ja see jõudlus laieneb olemasolevatele tuumadele. See tähendab, et kui teil on näiteks 20 tuuma, siis skannite miljard punkti sekundis. Ja see VictoriaMetricsi ja ClickHouse'i omadus vähendab allasammutamise vajadust.

Veel üks omadus on see, et VictoriaMetrics tihendab need andmed tõhusalt. Tootmises on tihendus keskmiselt 0,4–0,8 baiti punkti kohta. Iga punkt on ajatempel + väärtus. Ja see tihendatakse keskmiselt vähem kui üheks baidiks.

Sergei. Mul on küsimus. Mis on minimaalne salvestusaja kvantum?

Üks millisekund. Meil oli hiljuti vestlus teiste aegridade andmebaasi arendajatega. Nende minimaalne ajalõik on üks sekund. Ja näiteks grafiidis on see ka üks sekund. OpenTSDB-s on see samuti üks sekund. InfluxDB on nanosekundi täpsusega. VictoriaMetricsis on see üks millisekund, kuna Prometheuses on see üks millisekund. Ja VictoriaMetrics töötati algselt välja Prometheuse kaugsalvestuseks. Kuid nüüd saab see salvestada andmeid teistest süsteemidest.

Inimene, kellega ma rääkisin, ütleb, et neil on sekundist sekundini täpsus – sellest piisab, sest see sõltub aegridade andmebaasi salvestatavate andmete tüübist. Kui tegemist on DevOpsi andmete või infrastruktuuri andmetega, kuhu kogute neid 30-sekundiliste intervallidega minutis, siis piisab sekundilisest täpsusest, vähem polegi vaja. Ja kui kogute neid andmeid kõrgsageduskaubandussüsteemidest, siis vajate nanosekundi täpsust.

VictoriaMetricsi millisekundiline täpsus sobib ka DevOpsi juhtumi jaoks ja võib sobida enamiku juhtumite jaoks, mida mainisin aruande alguses. Ainus, mille jaoks see ei pruugi sobida, on kõrgsageduslikud kauplemissüsteemid.

Aitäh! Ja veel üks küsimus. Mis on PromQL-i ühilduvus?

Täielik tagasiühilduvus. VictoriaMetrics toetab täielikult PromQL-i. Lisaks lisab see PromQL-i täiendavaid täiustatud funktsioone, mida nimetatakse MetricsQL. YouTube'is räägitakse sellest laiendatud funktsioonist. Rääkisin kevadel Peterburis toimunud Monitoring Meetupil.

Telegrammi kanal VictoriaMetrics.

Küsitluses saavad osaleda ainult registreerunud kasutajad. Logi sissepalun.

Mis takistab teil Prometheuse pikaajaliseks salvestusruumiks VictoriaMetricsile üle minemast? (Kirjutage kommentaaridesse, lisan selle küsitlusesse))

  • 71,4%Ma ei kasuta Prometheus5

  • 28,6%Ei teadnud VictoriaMetrics2-st

7 kasutajat hääletas. 12 kasutajat jäi erapooletuks.

Allikas: www.habr.com

Lisa kommentaar