{"id":80733,"date":"2020-05-08T13:42:31","date_gmt":"2020-05-08T11:42:31","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin"},"modified":"2020-05-08T13:42:31","modified_gmt":"2020-05-08T11:42:31","slug":"go-optimizations-in-victoriametrics-aleksandr-valyalkin","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","title":{"rendered":"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Predlagam, da se seznanite z razvojem poro\u010dila iz konca leta 2019 Aleksandra Valjalkina \"Go optimizations in VictoriaMetrics\"<\/strong><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/victoriametrics.com\/\">VictoriaMetrics<\/a><\/noindex> \u2014 hitra in skalabilna SDB za shranjevanje in obdelavo podatkov v obliki \u010dasovnih vrst (vnos oblikuje \u010das in niz vrednosti, ki ustrezajo temu \u010dasu, na primer, pridobljenih preko periodi\u010dnega nadzora stanja senzorjev ali zbiranja metrik).<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/dd13ec10594aeb138be29ce439cc476a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Tukaj je povezava na video tega poro\u010dila \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/MZ5P21j_HLE\">https:\/\/youtu.be\/MZ5P21j_HLE<\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.google.com\/presentation\/d\/1k7OjHvxTHA7669MFwsNTCx8hII-a8lNvpmQetLxmrEU\/edit?usp=sharing\">Diapozitivi<\/a><\/noindex><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/0073390d6dbcc6ab3e5305907ac6a229.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Najprej bom nekaj povedal o sebi. Sem Aleksander Valjalkin. Tukaj je <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/valyala\">moj GitHub ra\u010dun<\/a><\/noindex>. Rad se ukvarjam z Go in optimizacijo zmogljivosti. Napisal sem \u0161tevilne uporabne in ne tako uporabne knji\u017enice. Te se za\u010dnejo bodisi z <code>fast<\/code>, ali z <code>quick<\/code> predpono. <\/p>\n<p><\/p>\n<p>Trenutno delam na VictoriaMetrics. Kaj je to in kaj tam delam? O tem bom govoril v tej predstavitvi. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c9194bc3fee1f615d838979bec12f7d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na\u010drt poro\u010dila je naslednji:<\/p>\n<p><\/p>\n<ul>\n<li>Na za\u010detku vam bom predstavil, kaj je VictoriaMetrics. <\/li>\n<li>Potem bom razlo\u017eil, kaj so \u010dasovne vrste. <\/li>\n<li>Nato bom razlo\u017eil, kako deluje zbirka podatkov \u010dasovnih vrst.<\/li>\n<li>Nato bom govoril o arhitekturi zbirke podatkov: iz \u010desa je sestavljena.<\/li>\n<li>In potem bomo pre\u0161li k optimizacijam, ki jih ima VictoriaMetrics. To sta optimizacija obrnjenega indeksa in optimizacija za bitset-implementacijo v Go.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/3e0244b6b6fe952f660e4a094778921a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ali kdo v ob\u010dinstvu pozna VictoriaMetrics? Uau, \u017ee veliko ljudi ve. To je dobra novica. Za tiste, ki ne vedo \u2013 to je zbirka podatkov za \u010dasovne vrste. Temelji na arhitekturi ClickHouse, na nekaterih podrobnostih implementacije ClickHouse-a. Na primer, na takih, kot so: MergeTree, vzporedno ra\u010dunanje na vseh razpolo\u017eljivih jedrih procesorja in optimizacija zmogljivosti z delom na blokih podatkov, ki se shranijo v procesorskem predpomnilniku. <\/p>\n<p><\/p>\n<p>VictoriaMetrics zagotavlja bolj\u0161e stiskanje podatkov v primerjavi z drugimi zbirkami podatkov za \u010dasovne vrste. <\/p>\n<p><\/p>\n<p>Poleg tega se VictoriaMetrics vertikalno skalira \u2014 torej lahko dodate ve\u010d procesorjev, ve\u010d pomnilnika na enem ra\u010dunalniku. VictoriaMetrics bo uspe\u0161no koristila te razpolo\u017eljive vire in izbolj\u0161ala linearno zmogljivost.<\/p>\n<p><\/p>\n<p>VictoriaMetrics se tudi horizontalno skalira \u2014 torej lahko dodate dodatne vozli\u0161\u010da v grozd VictoriaMetrics in njena zmogljivost se bo skoraj linearno pove\u010devala.<\/p>\n<p><\/p>\n<p>Kot ste uganili, je VictoriaMetrics hitra zbirka podatkov, ker drugih ne morem pisati. In napisana je v Go, zato o njej govorim na tem sre\u010danju.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/0121c9baead722eb1fe22fb6f900d4ad.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kdo ve ve\u017e jo zna, kaj je \u010dasovna vrsta? Tudi veliko ljudi ve. \u010casovna vrsta je zaporedje parov <code>(\u010dasovni \u017eig, vrednost)<\/code>, kjer so ti pari razvr\u0161\u010deni po \u010dasu. Vrednost predstavlja \u0161tevilo s plavajo\u010do vejico \u2013 float64.<\/p>\n<p><\/p>\n<p>Vsaka \u010dasovna vrsta je edinstveno identificirana s klju\u010dem. Iz \u010desa je sestavljen ta klju\u010d? Sestavljen je iz nepraznega niza parov klju\u010d-vrednost. <\/p>\n<p><\/p>\n<p>Tukaj je primer \u010dasovne vrste. Klju\u010d te vrste je seznam parov: <code>__name__=\"cpu_usage\"<\/code> \u2013 to je ime metrike, <code>instance=\"my-server\"<\/code> \u2014 to je ra\u010dunalnik, na katerem je ta metrika zbrana, <code>datacenter=\"us-east\"<\/code> \u2014 to je podatkovni center, kjer se nahaja ta ra\u010dunalnik.<\/p>\n<p><\/p>\n<p>Imamo ime \u010dasovne vrste, sestavljeno iz treh parov klju\u010d-vrednost. Ta klju\u010d ustreza seznamu par <code>(\u010dasovni \u017eig, vrednost)<\/code>. <code>t1, t3, t3, ..., tN<\/code> \u2014 to so \u010dasovni \u017eigi, <code>10, 20, 12, ..., 15<\/code> \u2014 ustrezne vrednosti. To je cpu-usage v tem trenutku za to vrsto.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/76cab9db0263318d355ac607ceb7e0f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kje se lahko uporabijo \u010dasovne vrste? Ima kdo kak\u0161ne ideje? <\/p>\n<p><\/p>\n<ul>\n<li>V DevOps lahko merimo obremenitve CPU, RAM, omre\u017eja, rps, \u0161tevilo napak itd. <\/li>\n<li>IoT \u2013 lahko merimo temperaturo, pritisk, geografske koordinate in \u0161e kaj.<\/li>\n<li>Prav tako finance \u2013 lahko spremljamo cene razli\u010dnih delnic in valut. <\/li>\n<li>Poleg tega se \u010dasovne vrste lahko uporabljajo za spremljanje proizvodnih procesov v tovarnah. Imamo uporabnike, ki uporabljajo VictoriaMetrics za spremljanje vetrnih turbin, za robote.<\/li>\n<li>\u010casovne vrste so prav tako uporabne za zbiranje informacij s senzorjev razli\u010dnih naprav. Na primer, za motor; za merjenje pritiska v pnevmatikah; za merjenje hitrosti, razdalje; za merjenje porabe benzina itd.<\/li>\n<li>\u010casovne vrste se lahko uporabljajo tudi za spremljanje letal. Vsako letalo ima \u010drno skrinjico, ki zbira \u010dasovne vrste po razli\u010dnih parametrih zdravja letala. \u010casovne vrste se prav tako uporabljajo v vesoljski industriji. <\/li>\n<li>Zdravstvo \u2013 to so krvni tlak, pulz itd.<\/li>\n<\/ul>\n<p><\/p>\n<p>Morda so \u0161e druge uporabe, o katerih sem pozabil, ampak upam, da ste razumeli, da se \u010dasovne vrste aktivno uporabljajo v sodobnem svetu. In obseg njihove uporabe nara\u0161\u010da iz leta v leto.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/f1da29d372163751268b6a8f86836d04.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zakaj potrebujemo bazo podatkov za \u010dasovne vrste? Zakaj ne moremo uporabiti obi\u010dajne relacijske baze za shranjevanje \u010dasovnih vrst?<\/p>\n<p><\/p>\n<p>Ker pa so v \u010dasovnih vrstah ponavadi velike koli\u010dine informacij, ki jih je te\u017eko shraniti in obdelati v obi\u010dajnih podatkovnih bazah. Zato so nastale specializirane Baza podatkov za \u010dasovne vrste. Te baze u\u010dinkovito shranjujejo to\u010dke <code>(\u010dasovni \u017eig, vrednost)<\/code> s predvideno klju\u010dno besedo. Nudijo API za branje shranjenih podatkov po klju\u010dno besedo, po eni par klju\u010dno-vrednost, bodisi po ve\u010d takih parih, bodisi po regexp. Na primer, \u010de \u017eelite najti obremenitev procesorja vseh va\u0161ih storitev v podatkovnem centru v Ameriki, morate uporabiti tak\u0161en psedoklic.<\/p>\n<p><\/p>\n<p>Obi\u010dajno podatkovne baze za \u010dasovne vrste predstavljajo specializirani jeziki poizvedb, ker SQL za \u010dasovne vrste ni najbolj primeren. \u010ceprav obstajajo podatkovne baze, ki podpirajo SQL, ta ni najbolj primeren. Bolj primerni so jeziki poizvedb, kot so <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@valyala\/promql-tutorial-for-beginners-9ab455142085\">PromQL<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.influxdata.com\/influxdb\/v1.8\/query_language\/spec\/\">InfluxQL<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.influxdata.com\/products\/flux\/\">Flux<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/code.kx.com\/q\/\">Q<\/a><\/noindex>. Upam, da je nekdo vsaj s katerim od teh jezikov \u017ee sli\u0161al. O PromQL verjetno marsikdo \u017ee ve. To je jezik poizvedb Prometheus.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/59e5b6d82a2f7861077bc5fe34519ee4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tako izgleda arhitektura sodobne podatkovne baze za \u010dasovne vrste na primeru VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Sestavljena je iz dveh delov. To je skladi\u0161\u010de za inverzni indeks in skladi\u0161\u010de za vrednosti \u010dasovnih vrst. Ta skladi\u0161\u010da sta lo\u010dena. <\/p>\n<p><\/p>\n<p>Ko nova zapis pride v podatkovno bazo, najprej dostopamo do inverznega indeksa, da najdemo identifikator \u010dasovne vrste po dolo\u010denem naboru <code>label=value<\/code> za to metriko. Najdemo ta identifikator in shranimo vrednost v podatkovno skladi\u0161\u010de.<\/p>\n<p><\/p>\n<p>Ko pride kak\u0161na poizvedba za pridobitev podatkov iz TSDB, najprej dostopamo do inverznega indeksa. Pridobimo vse <code>timeseries_ids<\/code> zapise, ki ustrezajo danemu naboru <code>label=value<\/code>. Nato pridobimo vse potrebne podatke iz podatkovnega skladi\u0161\u010da, indeksiranega po <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/eb9b36fa3c6de2188b97b56ad3839b2c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poglejmo primer, kako podatkovna baza za \u010dasovne vrste obdela prihajajo\u010do select-poizvedbo.<\/p>\n<p><\/p>\n<ul>\n<li>Najprej pridobi vse <code>timeseries_ids<\/code> iz inverznega indeksa, ki vsebujejo predvidene pare <code>label=value<\/code>, ali ustrezajo danemu regularnemu izrazu.<\/li>\n<li>Nato pridobi vse podatkovne to\u010dke iz skladi\u0161\u010da podatkov za dolo\u010den \u010dasovni interval za najdene <code>timeseries_ids<\/code>.<\/li>\n<li>Po tem podatkovna baza izvede dolo\u010dena izra\u010dunavanja na teh podatkovnih to\u010dkah v skladu s poizvedbo uporabnika. In nato vrne odgovor.<\/li>\n<\/ul>\n<p><\/p>\n<p>V tej predstavitvi vam bom predstavil prvi del. To je iskanje <code>timeseries_ids<\/code> po inverznem indeksu. O drugi in tretji del si lahko ogledate kasneje <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">izvorne kode VictoriaMetrics<\/a><\/noindex>, ali pa po\u010dakajte, da pripravim druge predstavitve \ud83d\ude42<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/3a7dab707dd1defb9bc674a342052a03.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Za\u010dnimo z inverznim indeksom. Mnogim se lahko zdi, da je to preprosto. Kdo ve, kaj je inverzni indeks in kako deluje? O, \u017ee ni ve\u010d toliko ljudi. Poskusimo razumeti, kaj je to. <\/p>\n<p><\/p>\n<p>V resnici je vse preprosto. To je le slovar, ki prikazuje klju\u010d na vrednost. Kaj je klju\u010d? Ta par <code>label=value<\/code>, gde <code>label<\/code> in <code>value<\/code> \u2014 so nizi. In vrednosti so nabor <code>timeseries_ids<\/code>, ki vsebuje dolo\u010den par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Inverzni indeks omogo\u010da hitro iskanje vseh <code>timeseries_ids<\/code>, ki imajo dolo\u010den <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Prav tako omogo\u010da hitro iskanje <code>timeseries_ids<\/code> \u010dasovnih vrst za ve\u010d parov <code>label=value<\/code>, ali za pare <code>label=regexp<\/code>. Kako to deluje? S pomo\u010djo iskanja preseka mno\u017eice <code>timeseries_ids<\/code> za vsak par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/837a15a078e8c9422c721f3f072c0c09.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Poglejmo razli\u010dne implementacije inverznega indeksa. Za\u010deli bomo s najenostavnej\u0161o naivno implementacijo. Izgleda takole. <\/p>\n<p><\/p>\n<p>Funkcija <code>getMetricIDs<\/code> pridobi seznam nizov. Vsak niz vsebuje <code>label=value<\/code>. Ta funkcija vrne seznam <code>metricIDs<\/code>.<\/p>\n<p><\/p>\n<p>Kako to deluje? Tukaj imamo globalno spremenljivko, ki se imenuje <code>invertedIndex<\/code>. To je obi\u010dajen slovar (<code>map<\/code>), ki prikazuje niz na slice int-ov. Niz vsebuje <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Implementacija funkcije: pridobimo <code>metricIDs<\/code> za prvi <code>label=value<\/code>, nato pa preidemo skozi vse ostale <code>label=value<\/code>, pridobimo <code>metricIDs<\/code> zanje. In pokli\u010demo funkcijo <code>intersectInts<\/code>, o kateri bo govorjeno kasneje. In ta funkcija vrne presek teh seznamov.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/709beca79884a9693098781974c26f4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kot vidite, implementacija inverznega indeksa ni tako zapletena. Toda to je naivna implementacija. Kak\u0161ne so njene pomanjkljivosti? Glavna pomanjkljivost naivne implementacije je, da se tak inverzni indeks hrani v operativni pomnilniku. Po ponovnem zagonu aplikacije izgubimo ta indeks. Ni shranjevanja tega indeksa na disk. Za bazo podatkov ta inverzni indeks verjetno ne bo ustrezal.<\/p>\n<p><\/p>\n<p>Druga pomanjkljivost je prav tako povezana s pomnilnikom. Inverzni indeks mora biti shranjen v operativni pomnilnik. \u010ce prese\u017ee velikost operativnega pomnilnika, je o\u010ditno, da bomo dobili napako \u2013 out of memory error. In program ne bo deloval.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/495394168ac03aa8cbcf56ccad1cb2b8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To te\u017eavo lahko re\u0161imo s pomo\u010djo \u017ee pripravljenih re\u0161itev, kot so <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/google\/leveldb\">LevelDB<\/a><\/noindex>, ali <noindex><a rel=\"nofollow\" href=\"https:\/\/rocksdb.org\/\">RocksDB<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Na kratko, potrebujemo bazo podatkov, ki omogo\u010da hitro izvajanje treh operacij. <\/p>\n<p><\/p>\n<ul>\n<li>Prva operacija je zapisovanje <code>klju\u010d-vrednost<\/code> v to bazo. To po\u010dne zelo hitro, kjer <code>klju\u010d-vrednost<\/code> so poljubne vrstice. <\/li>\n<li>Druga operacija je hiter iskanje vrednosti po dolo\u010denem klju\u010du.<\/li>\n<li>In tretja operacija je hiter iskanje vseh vrednosti po dolo\u010denem prefiksu. <\/li>\n<\/ul>\n<p><\/p>\n<p>LevelDB in RocksDB sta zapisani v Google in Facebook. Najprej je pri\u0161el LevelDB. Potem so fantje iz Facebooka vzeli LevelDB in za\u010deli ga izbolj\u0161evati, naredili so RocksDB. Sedaj skoraj vse notranje baze podatkov znotraj Facebooka delujejo na RocksDB, tudi MySQL so prenesli na RocksDB. Poimenovali so ga <noindex><a rel=\"nofollow\" href=\"http:\/\/myrocks.io\/\">MyRocks<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Inverzni indeks lahko realiziramo s LevelDB. Kako to storiti? Klju\u010d shranimo <code>label=value<\/code>. In kot vrednost - identifikator \u010dasovne vrste, kjer je prisotna par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>\u010ce imamo veliko \u010dasovnih vrst s to par <code>label=value<\/code>, bo v tej bazi podatkov veliko vrstic z enakim klju\u010dem in razli\u010dnimi <code>timeseries_ids<\/code>. Da dobimo seznam vseh <code>timeseries_ids<\/code>, ki se za\u010dnejo s to <code>label=prefix<\/code>, izvedemo range scan, za katerega je ta baza podatkov optimizirana. T. j. izberemo vse vrstice, ki se za\u010dnejo s <code>label=prefix<\/code> in dobimo potrebne <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/a40877ecb758ac3bc1979bcd568d7e83.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tukaj je okvirna realizacija, kako bi izgledala v Go. Imamo inverzni indeks. To je LevelDB.<\/p>\n<p><\/p>\n<p>Funkcija je taka kot pri naivni realizaciji. Skoraj vrstica za vrstico ponavlja naivno realizacijo. Edini trenutek je, da namesto klicanja <code>map<\/code> se obra\u010damo na inverzni indeks. Dobimo vse vrednosti za prvi <code>label=value<\/code>. Potem pregledamo vse preostale pare <code>label=value<\/code> in dobimo ustrezne nize metricIDs zanje. Nato najdemo prese\u010di\u0161\u010de. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/de11b15286816ada04b22727ff78e43d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zveni dobro, a to re\u0161itev ima pomanjkljivosti. VictoriaMetrics je sprva realizirala inverzni indeks na osnovi LevelDB. A na koncu so se morale odre\u010di temu.<\/p>\n<p><\/p>\n<p>Zakaj? Ker je LevelDB po\u010dasnej\u0161i kot naivna realizacija. V naivni realizaciji ob danem klju\u010du takoj dobimo celoten slice <code>metricIDs<\/code>. To je zelo hitra operacija \u2014 celoten slice je pripravljen za uporabo.<\/p>\n<p><\/p>\n<p>Pri LevelDB pa je pri vsakem klicu funkcije <code>GetValues<\/code> potrebno prebrati vse vrstice, ki se za\u010dnejo s <code>label=value<\/code>. In za vsako vrstico dobiti vrednost <code>timeseries_ids<\/code>. Iz takih <code>timeseries_ids<\/code> zbiramo slice teh <code>timeseries_ids<\/code>. O\u010ditno je, da je to veliko po\u010dasneje kot preprosto dostopanje do navadne mape po klju\u010du.<\/p>\n<p><\/p>\n<p>Drugi nedostatak je to \u0161to je LevelDB napisan u C-u. Pozivanje C funkcija iz Go-a nije vrlo brzo. To traje stotine nanosekundi. To nije brzo jer se u pore\u0111enju sa obi\u010dnim pozivom funkcije napisanom u Go-u, koji traje 1-5 nanosekundi, razlika u performansama ispostavlja u desetinama puta. Za VictoriaMetrics, to je bio fatalni nedostatak \ud83d\ude42<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/47cace825807b7b062064c2e790dc9d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Zato sam napisao vlastitu implementaciju obrnute indeksa. I nazvao je <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/mergeset\">mergeset<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Mergeset se oslanja na strukturu podataka MergeTree. Ova struktura podataka je preuzeta iz ClickHouse. O\u010digledno je da mergeset treba biti optimizovan za brzo pretra\u017eivanje <code>timeseries_ids<\/code> po zadatom klju\u010du. Mergeset je napisan potpuno u Go-u. Mo\u017eete pogledati <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">izvore VictoriaMetrics na GitHub-u<\/a><\/noindex>. Implementacija mergeseta se nalazi u folderu <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/mergeset\">\/lib\/mergeset<\/a><\/noindex>. Mo\u017eete poku\u0161ati da shvatite \u0161ta se tamo de\u0161ava.<\/p>\n<p><\/p>\n<p>API mergeseta je veoma sli\u010dan LevelDB-u i RocksDB-u. Tj. omogu\u0107ava brzo \u010duvanje novih zapisa i brzo preuzimanje zapisa po zadatom prefiksu.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/845704ed36f70beb468907d22701af59.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>O nedostacima mergeseta \u0107emo razgovarati kasnije. Sada \u0107emo govoriti o problemima koji su nastali sa VictoriaMetrics u produkciji prilikom implementacije obrnute indeksa.<\/p>\n<p><\/p>\n<p>Za\u0161to su se javili?<\/p>\n<p><\/p>\n<p>Prvi razlog je visok churn rate. U prevodu na srpski \u2013 to je \u010desta promena vremenskih serija. To je kada vremenska serija zavr\u0161i i po\u010dne nova serija, ili po\u010dinje mnogo novih vremenskih serija. I to se doga\u0111a \u010desto.<\/p>\n<p><\/p>\n<p>Drugi razlog je veliko broj vremenskih serija. Isprva, kada je monitoring postajao popularan, broj vremenskih serija je bio mali. Na primer, za svako ra\u010dunalo je potrebno pratiti optere\u0107enje procesora, memorije, mre\u017ee i diska. 4 vremenske serije po ra\u010dunaru. Recimo da imate 100 ra\u010dunara i 400 vremenskih serija. To je vrlo malo. <\/p>\n<p><\/p>\n<p>Vremenom su ljudi smislili da se mo\u017ee meriti detaljnije informacije. Na primer, meriti optere\u0107enje ne celog procesora, ve\u0107 pojedina\u010dno svakog procesorskog jezgra. Ako imate 40 procesorskih jezgara, odgovaraju\u0107e, imate 40 puta vi\u0161e vremenskih serija za merenje optere\u0107enja procesora. <\/p>\n<p><\/p>\n<p>Ampak to \u0161e ni vse. Vsaka procesorska jedro ima lahko ve\u010d stanj, kot je stanje neaktivnosti (idle), ko miruje. Kot tudi delovanje v uporabni\u0161kem prostoru, delovanje v jedrnem prostoru in druga stanja. In vsako to stanje se prav tako lahko meri kot posamezna \u010dasovna vrsta. To dodatno pove\u010duje \u0161tevilo vrst za 7-8 krat.<\/p>\n<p><\/p>\n<p>Iz enega merila smo dobili 40 x 8 = 320 meril le za en ra\u010dunalnik. Pomno\u017eimo s 100 in dobimo 32 000 namesto 400. <\/p>\n<p><\/p>\n<p>Nato je pri\u0161el Kubernetes. In to je \u0161e poslab\u0161alo situacijo, ker lahko v Kubernetes gosti veliko razli\u010dnih storitev. Vsaka storitev v Kubernetesu je sestavljena iz mnogih podov. In vse to je treba spremljati. Poleg tega imamo stalno uvajanje novih razli\u010dic va\u0161ih storitev. Za vsako novo razli\u010dico je potrebno ustvariti nove \u010dasovne vrste. Na koncu se \u0161tevilo \u010dasovnih vrst eksponentno pove\u010duje in soo\u010damo se s te\u017eavo velikega \u0161tevila \u010dasovnih vrst, ki se imenuje high-cardinality. VictoriaMetrics se s tem uspe\u0161no spopada v primerjavi z drugimi podatkovnimi bazami za \u010dasovne vrste. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c11b7ce6d3294ae420243f72636af4b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Podrobneje bomo obravnavali high churn rate. Kaj povzro\u010da high churn rate v produkciji? Ker se nekatere vrednosti oznak in tagov nenehno spreminjajo.<\/p>\n<p><\/p>\n<p>Na primer, vzemimo Kubernetes, v katerem obstaja koncept <code>deployment<\/code>, tj. ko se izda nova razli\u010dica va\u0161e aplikacije. Razvijalci Kubernetes so nekako odlo\u010dili dodati id deploymenta v oznako.<\/p>\n<p><\/p>\n<p>Kaj je to povzro\u010dilo? To je povzro\u010dilo, da ob vsakem novem deploymentu vsi stari \u010dasovni nizi prekinjajo, namesto njih pa se za\u010dnejo novi \u010dasovni nizi z novo vrednostjo oznake. <code>deployment_id<\/code>. Tak\u0161nih vrst je lahko sto tiso\u010d in celo milijone.<\/p>\n<p><\/p>\n<p>Pomembna zna\u010dilnost vsega tega je, da se skupno \u0161tevilo \u010dasovnih vrst pove\u010duje, vendar \u0161tevilo \u010dasovnih vrst, ki so trenutno aktivne in prejemajo podatke, ostaja konstantno. To stanje se imenuje \u2013 high churn rate.<\/p>\n<p><\/p>\n<p>Osnovni problem high churn rate je zagotoviti stalno hitrost iskanja vseh \u010dasovnih vrst po dolo\u010denem nizu oznak v dolo\u010denem \u010dasovnem obdobju. Obi\u010dajno je to \u010dasovno obdobje zadnja ura ali zadnji dan. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/ac18482b87cc37624d163b30c68cf7be.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kako re\u0161iti ovaj problem? Evo prve opcije. To je da se invertovani indeks deli na nezavisne delove prema vremenu. Odnosno, prolazi neki vremenski interval, zavr\u0161avamo rad sa trenutnim invertovanim indeksom. I kreiramo novi invertovani indeks. Prolazi jo\u0161 jedan vremenski interval, kreiramo jo\u0161 jedan i tako dalje. <\/p>\n<p><\/p>\n<p>I prilikom pretrage ovih invertovanih indeksa pronalazimo skup invertovanih indeksa koji spadaju u zadati interval. I, shodno tome, biramo odatle id vremenskih serija. <\/p>\n<p><\/p>\n<p>To omogu\u0107ava u\u0161tedu resursa, jer ne treba da pregledamo delove koji ne spadaju u zadati interval. Odnosno, obi\u010dno, ako biramo podatke za poslednji sat, presko\u010dimo zahteve za prethodne vremenske intervale. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1afa3a88caa7423941ae3494b9cec706.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Postoji jo\u0161 jedna opcija za re\u0161enje ovog problema. To je da za svaki dan \u010duvamo posebnu listu id vremenskih serija koje su se pojavile tog dana.<\/p>\n<p><\/p>\n<p>Prednost ovog re\u0161enja u odnosu na prethodno re\u0161enje je u tome \u0161to ne dupliramo informacije o vremenskim serijama koje ne nestaju tokom vremena. One su stalno prisutne i ne menjaju se. <\/p>\n<p><\/p>\n<p>Mane su u tome \u0161to je takvo re\u0161enje slo\u017eenije za implementaciju i te\u017ee se debaguje. I VictoriaMetrics je izabrala ovo re\u0161enje. Tako je istorijski formirano. Ovo re\u0161enje tako\u0111e daje dobre rezultate, u pore\u0111enju s prethodnim. Jer ovo re\u0161enje nije implementirano zbog potrebe da se dupliraju podaci u svakoj particiji za vremenske serije koje se ne menjaju, tj. koje ne nestaju tokom vremena. VictoriaMetrics je prvobitno optimizovana za potro\u0161nju diskovnog prostora, a prethodna implementacija je pogor\u0161avala potro\u0161nju diskovnog prostora. A ovo re\u0161enje je bolje prilago\u0111eno za minimizaciju potro\u0161nje diskovnog prostora, pa je ono izabrano. <\/p>\n<p><\/p>\n<p>Morali smo se boriti s tim. Borba se svela na to da u ovoj implementaciji i dalje trebamo da biramo znatno ve\u0107i broj <code>timeseries_ids<\/code> za podatke nego kada je invertovani indeks podeljen prema vremenu.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/5b10e61aaa803428ed3bfe31815f09d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kako smo re\u0161ili ovaj problem? Re\u0161ili smo ga na originalan na\u010din \u2013 \u010duvanjem nekoliko identifikatora vremenskih serija u svakoj stavci invertovanog indeksa umesto jednog identifikatora. Odnosno, imamo klju\u010d <code>label=value<\/code>, ki se pojavlja v vsakem \u010dasovnem nizu. In zdaj shranjujemo ve\u010d <code>timeseries_ids<\/code> v eni zapis.<\/p>\n<p><\/p>\n<p>Tukaj je primer. V preteklosti smo imeli N zapisov, zdaj pa imamo en zapis, katerega predpona je enak kot pri vseh drugih. Prej\u0161nji zapis vsebuje vse id-je \u010dasovnih nizov. <\/p>\n<p><\/p>\n<p>To je omogo\u010dilo pove\u010danje hitrosti iskanja takega obrnjenega indeksa do 10-krat. In zmanj\u0161alo je porabo pomnilnika za predpomnilnik, ker zdaj shranjujemo niz <code>label=value<\/code> le enkrat v predpomnilniku, skupaj N-krat. In ta niz je lahko obse\u017een, \u010de imate v oznakah in etiketanadelkih dolge vrstice, ki jih tja obi\u010dajno dodaja Kubernetes.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/ae4f38a440203bad2d03cf2abd1faafe.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0160e ena mo\u017enost za pospe\u0161itev iskanja po obrnjenem indeksu je delitev. Ustvarjanje ve\u010d obrnjenih indeksov namesto enega in razdelitev podatkov med njimi po klju\u010di. To je niz <code>key=value<\/code> parov. Torej imamo ve\u010d neodvisnih obrnjenih indeksov, ki jih lahko povpra\u0161ujemo hkrati na ve\u010d procesorjih. Prej\u0161nje implementacije so omogo\u010dale delo le v enoprocesorskem na\u010dinu, tj. skeniranje podatkov le na eni jedru. To re\u0161itev omogo\u010da skeniranje podatkov hkrati na ve\u010d jeder, kar ClickHouse zelo rad po\u010dne. To nameravamo realizirati.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/5ced6446efbf8ded8d7fb91694a999b0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>In zdaj se vrnimo k na\u0161im ovsom \u2013 k funkciji preseka <code>timeseries_ids<\/code>. Oglejmo si, kak\u0161ne bi mogle biti implementacije. Ta funkcija omogo\u010da iskanje <code>timeseries_ids<\/code> za dolo\u010den niz <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/073a155018a91120c6996c324772f9af.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Prva mo\u017enost \u2013 to je naivna implementacija. Dva vgrajena cikla. Tukaj dobimo vhodne funkcije <code>intersectInts<\/code> dva slices \u2014 <code>a<\/code> in <code>b<\/code>. Na izhodu bi morala vrniti presek teh slices.<\/p>\n<p><\/p>\n<p>Naivna implementacija izgleda tako. Prehodimo skozi vse vrednosti iz slice <code>a<\/code>, znotraj tega cikla prehodimo skozi vse vrednosti slice <code>b<\/code>. In jih primerjamo. \u010ce se ujemata, smo na\u0161li presek. In ga shranimo v <code>result<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/b89dcbb4f6d73377f9cf4f50169d6dd7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kak\u0161ne so pomanjkljivosti? Kvadratna kompleksnost \u2013 to je njena glavna pomanjkljivost. Na primer, \u010de imate velikosti slice <code>a<\/code> in <code>b<\/code> ena milijon, ta funkcija nikoli ne bo vrnila odgovora. Ker bo morala opraviti en bilijon iteracij, kar je zelo veliko tudi za moderne ra\u010dunalnike.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/bad26b0092a2fd7fc813bcb79a9138ce.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Druga implementacija temelji na mapi. Ustvarimo mapo. V to mapo postavimo vse vrednosti iz slice <code>a<\/code>. Nato gremo skozi posebno zanko po slice <code>b<\/code>. In preverimo \u2013 ali je ta vrednost iz slice <code>b<\/code> v map. \u010ce obstaja, ga dodamo rezultatu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1e610acf641a9cfe4c80aac1fe26044c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Kak\u0161ne so prednosti? Prednost je v tem, da ima tukaj le linearno kompleksnost. To pomeni, da se funkcija izvede veliko hitreje za velike velikosti rezin. Za rezino z milijon elementi bo ta funkcija izvedena v 2 milijonih iteracij, medtem ko je pri prej\u0161nji funkciji potrebnih trikrat milijon iteracij.<\/p>\n<p><\/p>\n<p>Slabost pa je, da ta funkcija zahteva ve\u010d pomnilnika za ustvarjanje te map.<\/p>\n<p><\/p>\n<p>Druga slabost je velika obremenitev zaradi he\u0161iranja. Ta slabost ni tako o\u010ditna. Za nas ni bila prav tako o\u010ditna, zato je bila sprva v VictoriaMetrics implementacija preseka preko map. A kasneje je profiliranje pokazalo, da se ve\u010dina procesorskega \u010dasa porabi za zapisovanje v map in preverjanje obstoja vrednosti v tej map.<\/p>\n<p><\/p>\n<p>Zakaj se na teh mestih porablja procesorski \u010das? Ker v teh vrsticah Go izvaja operacijo he\u0161iranja. To pomeni, da izra\u010duna hash klju\u010da, da se nato lahko sklicuje na dolo\u010den indeks v HashMap. Operacija izra\u010duna hasha traja desetine nanosekund. To je za VictoriaMetrics po\u010dasi.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/969f10d875d88998e958894ca28b1181.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Odlo\u010dil sem se za implementacijo bitseta, optimiziranega posebej za ta primer. Tako zdaj izgleda prese\u010de dveh rezin. Tukaj ustvarimo bitset. Dodamo vanj elemente iz prve rezine. Potem preverimo prisotnost teh elementov v drugi rezini. In jih dodamo rezultatu. To pomeni, da se skoraj ne razlikuje od prej\u0161njega primera. Edina razlika je, da smo tukaj namesto obravnave z map uporabili prilagojene funkcije. <code>add<\/code> in <code>has<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/b4ec0753d30d9684868a031f605632c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na prvi pogled se zdi, da bi to moralo delovati po\u010dasneje, \u010de je bila prej uporabljena standardna map, zdaj pa se kli\u010dejo \u0161e dodatne funkcije, vendar profiliranje ka\u017ee, da ta stvar deluje 10-krat hitreje kot standardna map za primer VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Poleg tega porabi precej manj pomnilnika v primerjavi z implementacijo na map. Ker tukaj hranimo bite namesto osmobytnh vrednosti.<\/p>\n<p><\/p>\n<p>Slabost te implementacije pa je, da ni tako o\u010ditna, ni trivialna. <\/p>\n<p><\/p>\n<p>\u0160e en pomanjkljivost, ki jo mnogi morda ne opazijo, je, da ta implementacija morda v nekaterih primerih slabo deluje. To pomeni, da je optimizirana za specifi\u010den primer, v tem primeru za prekrivanje ids \u010dasovnih vrst VictoriaMetrics. To ne pomeni, da bo ustrezala vsem primerom. \u010ce jo bomo napa\u010dno uporabili, ne bomo dobili izbolj\u0161anja zmogljivosti, temve\u010d napako s pomanjkanjem pomnilnika in upo\u010dasnitev zmogljivosti. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/94bd174afe43e67b3cf279dc7a1be17c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Oglejmo si implementacijo te strukture. \u010ce \u017eelite pogledati, se nahaja v izvorih VictoriaMetrics, v mapi <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/uint64set\">lib\/uint64set<\/a><\/noindex>. Optimizirana je prav za primer VictoriaMetrics, kjer <code>timeseries_id<\/code> predstavlja 64-bitno vrednost, kjer prvih 32 bitov ostane konstantnih, spremeni se le zadnjih 32 bitov.<\/p>\n<p><\/p>\n<p>Ta podatkovna struktura se ne shranjuje na disk; deluje le v pomnilniku. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/e24ca65f860e2b04037e073f7acae0c1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tukaj je njen API. Ni zelo zapleten. API je prilagojen prav specifi\u010dnemu primeru uporabe VictoriaMetrics. To pomeni, da tukaj ni odve\u010dnih funkcij. Tukaj so funkcije, ki jih jasno uporablja VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Obstajajo funkcije <code>add<\/code>, ki dodaja nove vrednosti. Obstaja funkcija <code>has<\/code>, ki preverja nove vrednosti. In obstaja funkcija <code>del<\/code>, ki odstrani vrednosti. Obstaja pomo\u017ena funkcija <code>len<\/code>, ki vrne velikost mno\u017eice. Funkcija <code>clone<\/code> klonira mno\u017eico. In funkcija <code>appendto<\/code> pretvori to mno\u017eico v slice <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/874b04042d13f342d39f8f393e7fb78c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tako izgleda implementacija te podatkovne strukture. V set sta dva elementa:<\/p>\n<p><\/p>\n<ul>\n<li>\n<p><code>ItemsCount<\/code> \u2013 to je pomo\u017eno polje, da hitro vrnemo \u0161tevilo elementov v set. Brez tega pomo\u017enega polja bi se lahko odpravili, vendar smo ga morali dodati, ker VictoriaMetrics pogosto preverja dol\u017eino bitseta v svojih algoritmih.<\/p>\n<p>\n<\/li>\n<li>\n<p>Drugo polje je <code>buckets<\/code>. To je slice iz strukture <code>bucket32<\/code>. V vsaki strukturi je shranjeno <code>hi<\/code> polje. To so zgornji 32 bitov. In dva slice \u2014 <code>b16his<\/code> in <code>buckets<\/code> iz <code>bucket16<\/code> struktur. <\/p>\n<p>\n<\/li>\n<\/ul>\n<p><\/p>\n<p>Tukaj so shranjeni zgornji 16 bitov drugega dela 64-bitne strukture. Tukaj so bitseti za spodnjih 16 bitov vsakega bajta. <\/p>\n<p><\/p>\n<p><code>Bucket64<\/code> sestavlja niz <code>uint64<\/code>. Dol\u017eina se izra\u010duna s temi konstantami. V enem <code>bucket16<\/code> lahko maksimalno shrani <code>2^16=65536<\/code> bitov. \u010ce to delimo z 8, je to 8 kilobajtov. \u010ce to delimo \u0161e enkrat z 8, je to 1000 <code>uint64<\/code> vrednost. To pomeni, da <code>Bucket16<\/code> \u2013 to je 8-kilobajtna struktura. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1cca4e6bfafa3408a3c95e0118e26d80.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Oglejmo si, kako je implementiran eden od metod te strukture za dodajanje nove vrednosti. <\/p>\n<p><\/p>\n<p>Vse se za\u010dne s <code>uint64<\/code> vrednosti. Izra\u010dunavamo gornjih 32 bita, izra\u010dunavamo donjih 32 bita. Prolazimo kroz sve <code>buckets<\/code>. Upore\u0111ujemo gornjih 32 bita u svakom bucket-u s dodatim vrednostima. I ako se poklapaju, pozivamo funkciju <code>add<\/code> u strukturi b32 <code>buckets<\/code>. I dodajemo donjih 32 bita. I ako to vrati <code>true<\/code>, to zna\u010di da smo dodali tu vrednost i da nismo imali takvu vrednost. Ako vrati <code>false<\/code>, to zna\u010di da je takva vrednost ve\u0107 postojala. Potom pove\u0107avamo broj elemenata u strukturi. <\/p>\n<p><\/p>\n<p>Ako nismo prona\u0161li potrebnu <code>spremnik<\/code> s potrebnim hi-vrednostima, pozivamo funkciju <code>addAlloc<\/code>, koja alocira novu <code>spremnik<\/code>, dodaju\u0107i je u strukturu bucket-a.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c5d1e5de767f47c7c40e01e12b6d0617.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ovo je implementacija funkcije <code>b32.add<\/code>. Sli\u010dna je prethodnoj implementaciji. Izra\u010dunavamo gornjih 16 bita, donjih 16 bita.<\/p>\n<p><\/p>\n<p>Zatim prolazimo kroz sve gornjih 16 bita. Pronalazimo podudaranja. I kod podudaranja pozivamo metodu add, koju \u0107emo razmotriti na slede\u0107oj strani za <code>bucket16<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/e98c4ef316f3a894fd7019c3c85696f7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I ovo je najni\u017ei nivo, koji treba maksimalno optimizovati. Izra\u010dunavamo za <code>uint64<\/code> id vrednost u slice bit-u, kao i <code>bitmask<\/code>. To je maska za ovu 64-bitnu vrednost, pomo\u0107u koje mo\u017eemo proveriti da li je ovaj bit prisutan ili ga postaviti. Proveravamo prisutnost ovog bita, postavljamo ga i vra\u0107amo prisutnost. Ova implementacija nam omogu\u0107ava da ubrzamo operaciju preklapanja ids vremenskih serija 10 puta u pore\u0111enju sa obi\u010dnim mapama.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/4dfa5a6142829a3551be22d6c9c3ab92.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>U VictoriaMetrics, osim ove optimizacije, postoji mnogo drugih optimizacija. Ve\u0107ina ovih optimizacija dodana je ne bez razloga, ve\u0107 nakon profilisanja koda u produkciji.<\/p>\n<p><\/p>\n<p>To je glavno pravilo optimizacije \u2013 ne dodavati optimizaciju, pretpostavljaju\u0107i da \u0107e ovde biti usko mesto, jer se mo\u017ee ispostaviti da ne postoji usko mesto. Optimizacija obi\u010dno pogor\u0161ava kvalitet koda. Zato trebate optimizovati samo nakon profilisanja i po\u017eeljno u produkciji, tako da su to realni podaci. Kome je zanimljivo, mo\u017eete pogledati izvorne kodove VictoriaMetrics i istra\u017eiti druge optimizacije koje su tamo prisutne.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/7585c4dc782627bac5b649e6a55e2ffb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><em>Imam pitanje o bitset-u. Veoma podse\u0107a na implementaciju C++ vector bool, optimizovani bitset. Da li ste uzeli implementaciju odande?<\/em><\/p>\n<p><\/p>\n<p>Ne, ne od tam. Pri uresni\u010ditvi tega bitseta sem se orientiral na znanje strukture teh ids \u010dasovnih serij, ki se uporabljajo v VictoriaMetrics. Struktura je tak\u0161na, da so zgornji 32 biti ve\u010dinoma stalni. Spodnji 32 bita se lahko spreminjajo. \u010cim ni\u017eji bit, tem pogosteje se lahko spreminja. Zato je ta implementacija posebej optimizirana za to strukturo podatkov. C++ implementacija, kolikor vem, je optimizirana za splo\u0161ne primere. \u010ce optimizirate za splo\u0161ne primere, to pomeni, da ne bo najbolj optimalna za konkretne primere.<\/p>\n<p><\/p>\n<p>Priporo\u010dam, da si \u0161e ogledate predavanje Alekseja Milovida. Pred pribli\u017eno mesecem dni je govoril o optimizacijah v ClickHouse pod dolo\u010denimi specializacijami. Pove, da so splo\u0161ne C++ implementacije ali katerikoli druge implementacije prilagojene za dobro delovanje povpre\u010dno. Lahko delujejo slab\u0161e kot specializirane implementacije pod dolo\u010denimi znanji, kot jih imamo mi, ko vemo, da so zgornji 32 biti ve\u010dinoma stalni.<\/p>\n<p><\/p>\n<p><em>Imam drugo vpra\u0161anje. Katera so kardinalne razlike od InfluxDB?<\/em><\/p>\n<p><\/p>\n<p>Kardinalnih razlik je veliko. Glede zmogljivosti in porabe pomnilnika InfluxDB v testih ka\u017ee 10-krat ve\u010djo porabo pomnilnika za visoko kardinalne \u010dasovne serije, ko jih imate veliko, na primer milijone. Na primer, VictoriaMetrics porabi 1 GB na milijon aktivnih serij, medtem ko InfluxDB porabi 10 GB. To je velika razlika. <\/p>\n<p><\/p>\n<p>Druga kardinalna razlika je v tem, da ima InfluxDB \u010dudne jezike poizvedb - Flux in InfluxQL. Nista posebej priro\u010dna za delo s \u010dasovnimi serijami v primerjavi s <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@valyala\/promql-tutorial-for-beginners-9ab455142085\">PromQL<\/a><\/noindex>, ki ga podpira VictoriaMetrics. PromQL \u2013 to je jezik poizvedb iz Prometheusa.<\/p>\n<p><\/p>\n<p>In \u0161e ena razlika - InfluxDB ima nekoliko nenavaden model podatkov, kjer lahko vsaka vrstica hrani ve\u010d polj z razli\u010dnimi nabori oznak. Te vrstice so razdeljene \u0161e na razli\u010dne tabele. Ta dodatna zapletenost ote\u017euje kasnej\u0161e delo s to bazo. Te\u017eko jo je vzdr\u017eevati in razumeti.<\/p>\n<p><\/p>\n<p>V VictoriaMetrics je vse veliko bolj preprosto. Vsaka \u010dasovna serija predstavlja klju\u010d-vrednost. Vrednost je niz to\u010dk - <code>(\u010dasovni \u017eig, vrednost)<\/code>, klju\u010d pa je niz <code>label=value<\/code>. Ni\u010d ne lo\u010duje aktivnosti in meritve. To vam omogo\u010da, da izberete poljubne podatke in jih nato kombinirate, se\u0161tejete, od\u0161tejete, pomno\u017eite in delite, kar je v nasprotju z InfluxDB, kjer med razli\u010dnimi vrsticami \u0161e vedno niso uresni\u010dene nobene kalkulacije, kolikor vem. Tudi \u010de so uresni\u010dene, so zapletene, morate napisati kup kode. <\/p>\n<p><\/p>\n<p><em>Imam dodatno vpra\u0161anje. Sem prav razumel, da je bila neka te\u017eava, o kateri ste govorili, da ta inverzni indeks ne more stati v spominu, zato poteka particioniranje?<\/em><\/p>\n<p><\/p>\n<p>Na za\u010detku sem pokazal naivno izvedbo inverznega indeksa na standardni Go\u0161ki mapi. Tak\u0161na izvedba ni primerna za podatkovne baze, ker ta inverzni indeks ne ostane na disku, medtem ko mora podatkovna baza shranjevati na disk, da so ti podatki ob ponovnem zagonu dostopni. V tej izvedbi bo ob ponovnem zagonu aplikacije va\u0161 inverzni indeks izgubljen. In izgubili boste dostop do vseh podatkov, ker jih ne boste mogli najti. <\/p>\n<p><\/p>\n<p><em>Pozdravljeni! Hvala za predstavitev! Ime mi je Pavel. Sem iz podjetja Wildberries. Imamo nekaj vpra\u0161anj za vas. Prvo vpra\u0161anje. Kako menite, da bi bilo, \u010de bi izbrali na\u010delo pri zasnovi svoje aplikacije in podatke particionirali po \u010dasu, potem bi morda lahko izvajali preseke podatkov med iskanjem, ki temeljijo samo na tem, da so v eni particiji podatki za en \u010dasovni interval, tj. za en \u010dasovni razpon, tako da ne bi bilo treba skrbeti, da so kosi razli\u010dno razmetani? Drugo vpra\u0161anje \u2014 ker izvajate tak algoritem z bitsetom in vsemi ostalimi stvarmi, morda ste poskusili uporabiti procesorske instrukcije? Mogo\u010de ste poskusili tak\u0161ne optimizacije?<\/em><\/p>\n<p><\/p>\n<p>Na drugo takoj odgovorim. Do tega \u0161e nismo pri\u0161li. Ampak, \u010de bo treba, bomo pri\u0161li. A prvi, kak\u0161no je bilo vpra\u0161anje?<\/p>\n<p><\/p>\n<p><em>Razpravljali ste o dveh scenarijih. In rekli ste, da ste izbrali drugega s kompleksnej\u0161o implementacijo. In niste izbrali prvega, kjer so podatki particionirani po \u010dasu.<\/em> <\/p>\n<p><\/p>\n<p>Da. V prvem primeru bi bil skupni obseg indeksa ve\u010dji, ker bi morali v vsakem particiji shranjevati podvojene podatke za tiste \u010dasovne vrste, ki se nadaljujejo skozi vse te particije. In \u010de imate nizek churn rate \u010dasovnih vrst, tj. nenehno se uporabljajo iste vrste, bi v prvem primeru veliko bolj izgubili v zasedenem diskovnem prostoru v primerjavi z drugim primerom.<\/p>\n<p><\/p>\n<p>Tako da \u2013 da, particioniranje po \u010dasu je dobra izbira. To uporablja Prometheus. Vendar pa ima Prometheus \u0161e eno pomanjkljivost. Pri zdru\u017eevanju teh ko\u0161\u010dkov podatkov mora obdr\u017eati v pomnilniku meta-informacije o vseh oznakah in \u010dasovnih vrstah. Zato, \u010de so ko\u0161\u010dki podatkov veliki, ki jih zdru\u017euje, se poraba pomnilnika mo\u010dno pove\u010da pri zdru\u017eevanju, v nasprotju z VictoriaMetrics. Pri zdru\u017eevanju VictoriaMetrics sploh ne porabi pomnilnika, porabi le nekaj kilobajtov, ne glede na velikosti zdru\u017eevanih ko\u0161\u010dkov podatkov.<\/p>\n<p><\/p>\n<p><em>Algoritem, ki ga uporabljate, porabi pomnilnik. V njem so ozna\u010dene oznake \u010dasovnih vrst, na katerih so vrednosti. Na ta na\u010din preverjate parno prisotnost v enem nizu podatkov in v drugem. In razumete \u2013 ali je pri\u0161lo do preseka ali ne. Obi\u010dajno v bazah podatkov izvajajo kurzorje, iteratorje, ki hranijo svoje trenutno stanje in te\u010dejo po razvr\u0161\u010denih podatkih, kar omogo\u010da enostavno kompleksnost teh operacij.<\/em> <\/p>\n<p><\/p>\n<p>Zakaj ne uporabljamo kurzorjev za presek podatkov?<\/p>\n<p><\/p>\n<p><em>Da.<\/em> <\/p>\n<p><\/p>\n<p>Imamo v LevelDB ali v mergeset prava razvr\u0161\u010dena vrstica. Lahko gremo s kurzorjem in najdemo presek. Zakaj ne uporabljamo? Ker \u2013 je to po\u010dasi. Ker kurzorji predvidevajo, da je treba ob vsakem vrstici klicati funkcijo. Klic funkcije je 5 nanosekund. In \u010de imate 100.000.000 vrstic, potem porabimo pol sekunde samo za klic funkcije.<\/p>\n<p><\/p>\n<p><em>To je res, ja. In zadnje vpra\u0161anje imam. Vpra\u0161anje se morda zdi malo nenavadno. Zakaj ob vnosu podatkov ne moremo takoj izra\u010dunati vse potrebne agregate in jih shraniti v \u017eelenem oblikovanju? Zakaj shranjevati ogromne koli\u010dine v kak\u0161ne sisteme, kot so VictoriaMetrics, ClickHouse itd., da bi nato porabili veliko \u010dasa z njimi?<\/em><\/p>\n<p><\/p>\n<p><em>Dajem vam primjer kako bi to bilo jasnije. Recimo, kako radi mali igra\u010dka brzinomjer? On bilje\u017ei udaljenost koju ste pre\u0161li, cijelo vrijeme je dodaju\u0107i u jednu vrijednost, u drugu \u2013 vrijeme. I dijeli. I dobiva prosje\u010dnu brzinu. Mo\u017eete napraviti otprilike isto. Sabirati u letu sve potrebne \u010dinjenice.<\/em><\/p>\n<p><\/p>\n<p>Dobro, razumio sam pitanje. Va\u0161 primjer ima smisla. Ako znate koje vam agregate trebaju, to je najbolja implementacija. No problem je \u0161to ljudi pohranjuju te metrike, neke podatke u ClickHouse i ne znaju jo\u0161 kako \u0107e ih u budu\u0107nosti agregirati, filtrirati, pa moraju pohranjivati sve sirove podatke. Ali ako znate da trebate izra\u010dunati ne\u0161to prosje\u010dno, za\u0161to to ne biste izra\u010dunali, umjesto da spremate hrpu sirovih vrijednosti? No to je samo u slu\u010daju ako to\u010dno znate \u0161to vam treba.<\/p>\n<p><\/p>\n<p>Usput, baze za pohranu vremenskih serija podr\u017eavaju izra\u010dunavanje agregata. Na primjer, Prometheus podr\u017eava <noindex><a rel=\"nofollow\" href=\"https:\/\/prometheus.io\/docs\/prometheus\/latest\/configuration\/recording_rules\/\">pravila snimanja<\/a><\/noindex>. Odnosno, to se mo\u017ee u\u010diniti ako znate koji \u0107e vam agregati trebati. U VictoriaMetrics to jo\u0161 nije dostupno, ali obi\u010dno se ispred nje postavlja Prometheus, u kojem to mo\u017eete u\u010diniti s pravilima snimanja.<\/p>\n<p><\/p>\n<p>Na prethodnom poslu, bilo je potrebno izra\u010dunati broj doga\u0111aja u kliznom prozoru za posljednji sat. Problem je \u0161to smo morali raditi prilago\u0111enu implementaciju u Gou, tj. servis za izra\u010dunavanje ovog. Taj servis na kraju nije bio trivijalan, jer je te\u0161ko izra\u010dunati. Implementacija mo\u017ee biti jednostavna ako trebate izra\u010dunati neke aggregate na fiksnim vremenskim intervalima. No, ako \u017eelite izra\u010dunati doga\u0111aje u kliznom prozoru, to nije tako jednostavno kao \u0161to se \u010dini. Mislim da to jo\u0161 nije implementirano ni u ClickHouse-u ni u bazama vremenskih serija, jer je komplicirano za implementaciju.<\/p>\n<p><\/p>\n<p><em>I jo\u0161 jedno pitanje. Sada smo govorili o prosjeku i sjetio sam se da je nekada postojala stvar kao \u0161to je Graphite s backend-om Carbon. I on je mogao prorijediti stare podatke, tj. ostaviti jednu to\u010dku u minuti, jednu to\u010dku na sat itd. U na\u010delu, to je prili\u010dno prakti\u010dno ako su nam potrebni sirovi podaci, uvjetno govore\u0107i, za mjesec dana, a sve ostalo se mo\u017ee prorijediti. No, Prometheus i VictoriaMetrics ne podr\u017eavaju ovu funkcionalnost. Planira li se podr\u017eavati? Ako ne, za\u0161to?<\/em><\/p>\n<p><\/p>\n<p>Hvala na pitanju. Na\u0161i korisnici to povremeno postavljaju. Pitaju kada \u0107emo dodati podr\u0161ku za smanjivanje (downsampling). Tu je nekoliko problema. Prvo, svaki korisnik to shvata na svoj na\u010din: <code>downsampling<\/code> neko \u017eeli da dobije bilo koju proizvoljnu ta\u010dku na zadanom intervalu, neko \u017eeli maksimalne, minimalne, prose\u010dne vrednosti. Ako u va\u0161u bazu podataka pi\u0161e mnogo sistema, ne mo\u017ee ih se obraditi na isti na\u010din. Mo\u017ee se desiti da svaka sistema zahteva razli\u010dito smanjivanje. I to je te\u0161ko za implementaciju.<\/p>\n<p><\/p>\n<p>Drugo, VictoriaMetrics, kao i ClickHouse, optimizovana je za rad sa velikim obimima sirovih podataka, tako da mo\u017ee obraditi milijardu redova za manje od sekunde, ako imate mnogo jezgara u va\u0161em sistemu. Skener vremenskih serija u VictoriaMetrics \u2013 50.000.000 ta\u010daka u sekundi po jezgru. I ta performansa se skalira na dostupna jezgra. Dakle, ako imate 20 jezgara, na primer, dobi\u0107ete skeniranje milijarde ta\u010daka u sekundi. Ova osobina VictoriaMetrics i ClickHouse-a smanjuje potrebu za downsampling.<\/p>\n<p><\/p>\n<p>Jo\u0161 jedna osobina je ta \u0161to VictoriaMetrics efikasno kompresuje te podatke. Kompresija u proseku na produkciji iznosi od 0,4 do 0,8 bajta po ta\u010dki. Svaka ta\u010dka predstavlja timestamp + vrednost. I ona se kompresuje ispod jednog bajta u proseku. <\/p>\n<p><\/p>\n<p><em>Sergije. Imam pitanje. Koja je minimalna kvanta vremena za zapis?<\/em><\/p>\n<p><\/p>\n<p>Jedna milisekunda. Nedavno smo razgovarali sa drugim programerima baza podataka za vremenske serije. Njihova minimalna kvanta vremena je jedna sekunda. I u Graphite, na primer, tako\u0111e jedna sekunda. U OpenTSDB tako\u0111e jedna sekunda. U InfluxDB \u2013 nanosekundna preciznost. U VictoriaMetrics \u2013 jedna milisekunda, jer je u Prometheus jedna milisekunda. VictoriaMetrics je prvobitno razvijena kao udaljena pohrana za Prometheus. Ali sada mo\u017ee \u010duvati podatke i iz drugih sistema. <\/p>\n<p><\/p>\n<p>Osoba sa kojom sam razgovarao ka\u017ee da je njihova preciznost u sekundama \u2014 njima je to dovoljno, jer zavisi od tipa podataka koji se \u010duvaju u bazi vremenskih serija. Ako su to DevOps podaci ili podaci sa infrastrukture, gde ih prikupljate svakih 30 sekundi ili minute, tada je sekundna preciznost dovoljna, manje nije potrebno. A ako prikupljate te podatke iz sistema visokofrekventnog trgovanja, tada je potrebna nanosekundna preciznost.<\/p>\n<p><\/p>\n<p>Milisekundna preciznost u VictoriaMetrics odgovara DevOps slu\u010dajevima i mo\u017ee se koristiti za ve\u0107inu slu\u010dajeva koje sam spomenuo na po\u010detku izlaganja. Jedina situacija u kojoj mo\u017eda ne\u0107e odgovarati je visoko frekventno trgovanje.<\/p>\n<p><\/p>\n<p><em>Hvala! I jo\u0161 jedno pitanje. Kakva je kompatibilnost sa PromQL?<\/em><\/p>\n<p><\/p>\n<p>Potpuna obrnuta kompatibilnost. VictoriaMetrics potpuno podr\u017eava PromQL. Pored toga, dodaje dodatne napredne funkcionalnosti na PromQL, koja se naziva <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/wiki\/MetricsQL\">MetricsQL<\/a><\/noindex>. O ovoj dodatnoj funkcionalnosti postoji izlaganje na YouTubeu. Govorio sam o tome na Monitoring Meetup-u na prole\u0107e u Sankt Peterburgu.<\/p>\n<p><\/p>\n<p>Telegram kanal <noindex><a rel=\"nofollow\" href=\"https:\/\/t.me\/VictoriaMetrics_ru1\">VictoriaMetrics<\/a><\/noindex>.<\/p>\n<p class=\"for_users_only_msg\">Samo registrovani korisnici mogu u\u010destvovati u anketi. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Prijavite se<\/a><\/noindex>, molim vas.<\/p>\n<h2 class=\"default-block__polling-title\">\u0160ta vas spre\u010dava da pre\u0111ete na VictoriaMetrics kao dugoro\u010dno skladi\u0161te za Prometheus? (Pi\u0161ite u komentarima, dodao bih to u anketu))<\/h2>\n<ul class=\"poll-result\">\n<li class=\"poll-result__item\">\n<p>                <strong class=\"poll-result__data-percent  poll-result__data-percent_winner\">71,4%<\/strong>Ne koristim Prometheus5<\/p>\n<\/li>\n<li class=\"poll-result__item\">\n<p>                <strong class=\"poll-result__data-percent\">28,6%<\/strong>Nisam znao za VictoriaMetrics2<\/p>\n<\/li>\n<\/ul>\n<p>    Glasalo je 7 korisnika. Uzdr\u017ealo se 12 korisnika.<br \/>\n<br \/>Izvor: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/500844\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot; VictoriaMetrics \u2014 \u0431\u044b\u0441\u0442\u0440\u0430\u044f \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u0430\u044f \u0421\u0423\u0411\u0414 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430 (\u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u043d\u0430\u0431\u043e\u0440 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043e\u043f\u0440\u043e\u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u043b\u0438 \u0441\u0431\u043e\u0440 \u043c\u0435\u0442\u0440\u0438\u043a). \u0412\u043e\u0442 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u2014 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":80734,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-80733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Go optimizations in VictoriaMetrics. \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-08T11:42:31+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-08T11:42:31+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Go optimizacije u VictoriaMetrics. Aleksandar Valjalkin | ProHoster","description":"Predlagam, da se seznanite z razlago poro\u010dila iz konca leta 2019, ki ga je pripravil Aleksander Valjalkin \"Optimizacije Go v VictoriaMetrics\"","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Go optimizations in VictoriaMetrics. \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;","og:url":"https:\/\/prohoster.info\/sl\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-08T11:42:31+00:00","article:modified_time":"2020-05-08T11:42:31+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"80733","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:12:22","updated":"2022-09-29 05:16:51","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/80733","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=80733"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/80733\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/80734"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=80733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=80733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=80733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}