{"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\/hr\/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>Predla\u017eem da se upoznate sa transkriptom izlaganja Aleksandra Valjaljkina iz kraja 2019. godine \"Go optimizations in VictoriaMetrics\"<\/strong><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/victoriametrics.com\/\">VictoriaMetrics<\/a><\/noindex> \u2014 brza i skalabilna DBMS za pohranu i obradu podataka u obliku vremenskih serija (zapis stvara vrijeme i skup odgovaraju\u0107ih vrijednosti za to vrijeme, na primjer, dobivenih putem periodi\u010dkog pra\u0107enja stanja senzora ili prikupljanja metrika).<\/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>Evo linka na video ove prezentacije \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\">Slajdovi<\/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>Malo \u0107u vam re\u0107i o sebi. Ja sam Alexander Valjaljkin. Evo <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/valyala\">mog GitHub ra\u010duna<\/a><\/noindex>. Zanima me Go i optimizacija performansi. Napisao sam mnogo raznih korisnih i manje korisnih biblioteka. One zapo\u010dinju s <code>fast<\/code>, ili s <code>quick<\/code> prefiksom. <\/p>\n<p><\/p>\n<p>Trenutno radim na VictoriaMetrics. \u0160to je to i \u0161to tamo radim? O tome \u0107u govoriti u ovoj prezentaciji. <\/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>Plan prezentacije je sljede\u0107i:<\/p>\n<p><\/p>\n<ul>\n<li>Na po\u010detku \u0107u vam re\u0107i \u0161to je VictoriaMetrics. <\/li>\n<li>Zatim \u0107u objasniti \u0161to su vremenske serije. <\/li>\n<li>Potom \u0107u objasniti kako funkcionira baza podataka vremenskih serija.<\/li>\n<li>Nakon toga \u0107u pri\u010dati o arhitekturi baze podataka: od \u010dega se sastoji.<\/li>\n<li>A onda \u0107emo pre\u0107i na optimizacije koje postoje u VictoriaMetrics. To su optimizacija inverznog indeksa i optimizacija za bitset implementaciju u 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>Zna li netko u publici \u0161to je VictoriaMetrics? Izvrsno, puno ljudi zna. To je dobra vijest. Za one koji ne znaju \u2013 to je baza podataka za vremenske serije. Temelji se na arhitekturi ClickHouse, na nekim detaljima implementacije ClickHouse-a. Na primjer, na stvarima poput: MergeTree, paralelnog izvo\u0111enja na svim dostupnim jezgrama procesora i optimizacije performansi pomo\u0107u rada s blokovima podataka koji se stavljaju u CPU cache. <\/p>\n<p><\/p>\n<p>VictoriaMetrics nudi najbolje kompresije podataka u usporedbi s drugim bazama podataka za vremenske serije. <\/p>\n<p><\/p>\n<p>Vertikalno se skalira \u2014 tj. mo\u017eete dodavati ve\u0107i broj procesora, ve\u0107i broj radne memorije na jednom ra\u010dunalu. VictoriaMetrics \u0107e uspje\u0161no iskoristiti te dostupne resurse i pove\u0107ati linearnu u\u010dinkovitost.<\/p>\n<p><\/p>\n<p>VictoriaMetrics se tako\u0111er horizontalno skalira \u2014 tj. mo\u017eete dodavati dodatne \u010dvorove u klaster VictoriaMetrics, a njezina \u0107e se u\u010dinkovitost pove\u0107avati gotovo linearno.<\/p>\n<p><\/p>\n<p>Kao \u0161to ste pogodili, VictoriaMetrics je brza baza podataka, jer druge ne mogu opisati. I napisana je na Go-u, pa o njoj govorim na ovoj meet-up.<\/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>Tko zna \u0161to je vremenska serija? Tako\u0111er, puno ljudi zna. Vremenska serija \u2013 to je niz parova <code>(timestamp, vrijednost)<\/code>, gdje su ti parovi sortirani prema vremenu. Vrijednost predstavlja broj s pokretnom decimalom \u2013 float64.<\/p>\n<p><\/p>\n<p>Svaka vremenska serija jedinstveno je identificirana klju\u010dem. Od \u010dega se sastoji taj klju\u010d? Sastoji se od ne-praznog skupa parova klju\u010d-vrijednost. <\/p>\n<p><\/p>\n<p>Evo primjera vremenske serije. Klju\u010d ove serije je lista parova: <code>__name__=\"cpu_usage\"<\/code> \u2013 to je naziv metrike, <code>instance=\"my-server\"<\/code> \u2013 to je ra\u010dunar na kojem je ta metrika prikupljena, <code>datacenter=\"us-east\"<\/code> \u2013 to je data centar gdje se nalazi taj ra\u010dunar.<\/p>\n<p><\/p>\n<p>Dobijemo ime vremenske serije, sastavljeno od tri para klju\u010d-vrijednost. Ovom klju\u010du odgovara lista parova <code>(timestamp, value)<\/code>. <code>t1, t3, t3, ..., tN<\/code> \u2013 to su timestamps, <code>10, 20, 12, ..., 15<\/code> \u2013 odgovaraju\u0107e vrijednosti. Ovo je cpu-usage u trenutnom vremenu za tu seriju.<\/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>Gdje se mogu koristiti vremenske serije? Ima li netko ideje? <\/p>\n<p><\/p>\n<ul>\n<li>U DevOps-u mo\u017eemo mjeriti optere\u0107enje CPU-a, RAM-a, mre\u017ee, rps, broj gre\u0161aka itd. <\/li>\n<li>IoT \u2013 mo\u017eemo mjeriti temperaturu, tlak, geo koordinate i jo\u0161 puno toga.<\/li>\n<li>Tako\u0111er u financijama \u2013 mo\u017eemo pratiti cijene na razne dionice i valute. <\/li>\n<li>Osim toga, vremenske serije mogu se koristiti za pra\u0107enje proizvodnih procesa u tvornicama. Imamo korisnike koji koriste VictoriaMetrics za pra\u0107enje vjetroturbina, za robote.<\/li>\n<li>Tako\u0111er, vremenske serije su korisne za prikupljanje informacija s senzora raznih ure\u0111aja. Na primjer, za motor; za mjerenje tlaka u gumama; za mjerenje brzine, udaljenosti; za mjerenje potro\u0161nje benzina itd.<\/li>\n<li>Tako\u0111er, vremenske serije mogu se koristiti za pra\u0107enje aviona. U svakom avionu postoji crna kutija koja prikuplja vremenske serije o raznim parametrima zdravlja aviona. Vremenske serije se tako\u0111er koriste u zrakoplovnoj industriji. <\/li>\n<li>Zdravstvo \u2013 to su krvni tlak, puls itd.<\/li>\n<\/ul>\n<p><\/p>\n<p>Mo\u017eda postoje jo\u0161 primjene za koje sam zaboravio, ali se nadam da ste shvatili da se vremenske serije aktivno koriste u suvremenom svijetu. A njihova upotreba raste svake godine.<\/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>Za\u0161to je potrebna baza podataka za vremenske serije? Za\u0161to nije mogu\u0107e koristiti obi\u010dnu relacijsku bazu za pohranu vremenskih serija?<\/p>\n<p><\/p>\n<p>Zato \u0161to vremenske serije obi\u010dno sadr\u017ee velike koli\u010dine informacija koje je te\u0161ko pohraniti i obraditi u obi\u010dnim bazama podataka. Stoga su se pojavile specijalizirane baze podataka za vremenske serije. Ove baze u\u010dinkovito pohranjuju to\u010dke <code>(timestamp, value)<\/code> s zadanim klju\u010dem. One pru\u017eaju API za \u010ditanje pohranjenih podataka po klju\u010du, po jednoj parom klju\u010d-vrijednost, ili po nekoliko takvih parova, ili po regexp-u. Na primjer, ako \u017eelite prona\u0107i optere\u0107enje procesora svih va\u0161ih usluga u podatkovnom centru u Americi, tada trebate koristiti ovakav pseudo-upit.<\/p>\n<p><\/p>\n<p>Obi\u010dno baze podataka za vremenske serije nude specijalizirane jezike upita, jer SQL za vremenske serije nije ba\u0161 najbolje prilago\u0111en. Iako postoje baze podataka koje podr\u017eavaju SQL, on se ne uklapa najbolje. Bolje odgovaraju jezici upita poput <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>. Nadam se da je netko \u010duo barem za jedan od ovih jezika. O PromQL-u su vjerojatno mnogi \u010duli. To je jezik upita Prometheusa.<\/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>Evo kako izgleda arhitektura moderne baze podataka za vremenske serije na primjeru VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Ona se sastoji od dva dijela. To je skladi\u0161te za inverzivni indeks i skladi\u0161te za vrijednosti vremenskih serija. Ova skladi\u0161ta su odvojena. <\/p>\n<p><\/p>\n<p>Kada nova stavka do\u0111e u bazu podataka, prvo se obra\u0107amo inverzivnom indeksu kako bismo prona\u0161li identifikator vremenske serije prema zadanom skupu <code>label=value<\/code> za ovu metriku. Pronalazimo taj identifikator i pohranjujemo vrijednost u skladi\u0161tu podataka.<\/p>\n<p><\/p>\n<p>Kada do\u0111e neki upit za dohvat podataka iz TSDB, prvo \u0161to radimo je da zavirimo u inverzivni indeks. Izvla\u010dimo sve <code>timeseries_ids<\/code> zapise koji odgovaraju danom skupu. <code>label=value<\/code>I potom izvla\u010dimo sve potrebne podatke iz skladi\u0161ta podataka indeksiranog 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>Razmotrimo primjer kako baza podataka za vremenske serije obra\u0111uje dolazni select-upit.<\/p>\n<p><\/p>\n<ul>\n<li>Prvo dobijamo sve <code>timeseries_ids<\/code> iz inverzivnog indeksa koji sadr\u017ee zadan par <code>label=value<\/code>, ili udovoljavaju zadanom regularnom izrazu.<\/li>\n<li>Nakon toga izvla\u010dimo sve data points iz skladi\u0161ta podataka za zadani vremenski interval za prona\u0111ene <code>timeseries_ids<\/code>.<\/li>\n<li>Nakon toga, baza podataka vr\u0161i odre\u0111ene prora\u010dune nad tim data pointima prema korisni\u010dkom zahtevu. I zatim vra\u0107a odgovor.<\/li>\n<\/ul>\n<p><\/p>\n<p>U ovoj prezentaciji \u0107u vam pri\u010dati o prvom delu. To je pretra\u017eivanje <code>timeseries_ids<\/code> prema invertovanom indeksu. O drugom i tre\u0107em delu mo\u017eete pogledati kasnije <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">izvornike VictoriaMetrics<\/a><\/noindex>, ili da sa\u010dekate da pripravim druge izve\u0161taje \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>Krenimo prema invertovanom indeksu. Mnogima se mo\u017ee \u010diniti da je to jednostavno. Ko zna \u0161ta je invertovani indeks i kako funkcioni\u0161e? Oh, ve\u0107 nije toliki broj ljudi. Poku\u0161ajmo da shvatimo \u0161ta je to. <\/p>\n<p><\/p>\n<p>Zapravo, sve je jednostavno. To je samo re\u010dnik koji povezuje klju\u010deve s vrednostima. \u0160ta je klju\u010d? Ta \u0161ifra <code>label=value<\/code>, gdje <code>label<\/code> i <code>value<\/code> \u2014 to su stringovi. A vrednosti su skup <code>timeseries_ids<\/code>, koji uklju\u010duje zadanu \u0161ifru <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Invertovani indeks omogu\u0107ava brzo pronala\u017eenje svih <code>timeseries_ids<\/code>, koji imaju zadate <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Tako\u0111e omogu\u0107ava brzo pronala\u017eenje <code>timeseries_ids<\/code> vremenskih serija za nekoliko parova <code>label=value<\/code>, ili za parove <code>label=regexp<\/code>. Kako to funkcioni\u0161e? Pomo\u0107u pronala\u017eenja preseka seta <code>timeseries_ids<\/code> za svaki 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>Razmotrite razli\u010dite implementacije invertovanog indeksa. Po\u010dnimo s najjednostavnijom naivnom implementacijom. Izgleda ovako. <\/p>\n<p><\/p>\n<p>Funkcija <code>getMetricIDs<\/code> dobi\u0107e listu stringova. Svaki string sadr\u017ei <code>label=value<\/code>. Ova funkcija vra\u0107a listu <code>metricIDs<\/code>.<\/p>\n<p><\/p>\n<p>Kako to funkcioni\u0161e? Ovde imamo globalnu promenljivu koja se zove <code>invertedIndex<\/code>. To je obi\u010dan re\u010dnik (<code>map<\/code>), koji povezuje string s slice-om int-ova. String sadr\u017ei <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Implementacija funkcije: uzimamo <code>metricIDs<\/code> za prvi <code>label=value<\/code>, zatim prolazimo kroz sve ostale <code>label=value<\/code>, uzimamo <code>metricIDs<\/code> za njih. I pozivamo funkciju <code>intersectInts<\/code>, o kojoj \u0107e biti re\u010di kasnije. I ova funkcija vra\u0107a presek ovih listi.<\/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>Kao \u0161to vidite, implementacija invertovanog indeksa nije previ\u0161e slo\u017eena. Ali to je naivna implementacija. Koji su njeni nedostaci? Glavni nedostatak naivne implementacije je to \u0161to se takav invertovani indeks \u010duva u radnoj memoriji. Nakon ponovnog pokretanja aplikacije gubimo ovaj indeks. Nema \u010duvanja ovog indeksa na disku. Za bazu podataka takav invertovani indeks te\u0161ko da \u0107e odgovarati.<\/p>\n<p><\/p>\n<p>Drugi nedostatak tako\u0111er je povezan s memorijom. Inverzni indeks mora biti smje\u0161ten u radnu memoriju. Ako prema\u0161i veli\u010dinu radne memorije, jasno je da \u0107emo dobiti \u2013 gre\u0161ku zbog nedostatka memorije. Program ne\u0107e raditi.<\/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>Ovaj problem mo\u017ee se rije\u0161iti pomo\u0107u gotovih rje\u0161enja kao \u0161to su <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/google\/leveldb\">LevelDB<\/a><\/noindex>, ili <noindex><a rel=\"nofollow\" href=\"https:\/\/rocksdb.org\/\">RocksDB<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Ukratko, potrebna nam je baza podataka koja omogu\u0107uje brzo izvo\u0111enje tri operacije. <\/p>\n<p><\/p>\n<ul>\n<li>Prva operacija je zapis <code>klju\u010d-vrijednost<\/code> u ovu bazu. Ona to radi vrlo brzo, gdje <code>klju\u010d-vrijednost<\/code> \u2013 to su proizvoljni stringovi. <\/li>\n<li>Druga operacija je brzo pretra\u017eivanje vrijednosti po zadanom klju\u010du.<\/li>\n<li>I tre\u0107a operacija je brzo pretra\u017eivanje svih vrijednosti prema zadanom prefiksu. <\/li>\n<\/ul>\n<p><\/p>\n<p>LevelDB i RocksDB \u2013 ove baze razvijene su u Googleu i Facebooku. Prvo je nastao LevelDB. Nakon toga, momci iz Facebooka su uzeli LevelDB i po\u010deli ga pobolj\u0161avati, stvaraju\u0107i RocksDB. Trenutno se gotovo sve unutarnje baze podataka u Facebooku temelje na RocksDB, uklju\u010duju\u0107i i prebacivanje MySQL na RocksDB. Nazvali su to <noindex><a rel=\"nofollow\" href=\"http:\/\/myrocks.io\/\">MyRocks<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Inverzni indeks mo\u017ee se implementirati pomo\u0107u LevelDB. Kako to u\u010diniti? Spremamo kao klju\u010d <code>label=value<\/code>. A kao vrijednost \u2013 identifikator vremenskog niza u kojem postoji par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Ako imamo mnogo vremenskih nizova s ovom parom <code>label=value<\/code>, bit \u0107e mnogo redaka u ovoj bazi podataka s istim klju\u010dem i razli\u010ditim <code>timeseries_ids<\/code>. Da bismo dobili popis svih <code>timeseries_ids<\/code>, koji po\u010dinju s ovim <code>label=prefix<\/code>, radimo range scan, za koji je ova baza podataka optimizirana. Dakle, odabiremo sve retke koji po\u010dinju s <code>label=prefix<\/code> i dobijamo 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>Evo okvirne implementacije, kako bi ona izgledala na Go. Imamo inverzni indeks. To je LevelDB.<\/p>\n<p><\/p>\n<p>Funkcija je ista kao za naivnu implementaciju. Gotovo se redak po redak ponavlja naivna implementacija. Jedina razlika je ta \u0161to umjesto pristupanja <code>map<\/code> pristupamo inverznom indeksu. Izvla\u010dimo sve vrijednosti za prvi <code>label=value<\/code>. Zatim prolazimo kroz sve preostale parove <code>label=value<\/code> i izvla\u010dimo odgovaraju\u0107e skupove metricIDs za njih. Zatim nalazimo presjek. <\/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>\u010cini se da je sve u redu, ali ovo rje\u0161enje ima nedostatke. VictoriaMetrics je u po\u010detku implementirala inverzni indeks temeljen na LevelDB. No, na kraju je morala odustati od njega.<\/p>\n<p><\/p>\n<p>Za\u0161to? Zato \u0161to je LevelDB sporiji od naivne implementacije. U naivnoj implementaciji prema zadanoj klju\u010dnoj rije\u010di odmah dobijamo cijeli slice. <code>metricIDs<\/code>. Ova vrlo brza operacija \u2014 cijeli slice je spreman za kori\u0161tenje.<\/p>\n<p><\/p>\n<p>U LevelDB-u se prilikom svakog poziva funkcije <code>GetValues<\/code> mora pro\u0107i kroz sve redove koji po\u010dinju s <code>label=value<\/code>. I za svaki redak izvu\u0107i vrijednost <code>timeseries_ids<\/code>. Iz takvih <code>timeseries_ids<\/code> sakupiti slice ovih <code>timeseries_ids<\/code>. O\u010digledno, to je mnogo sporije od jednostavnog pristupa uobi\u010dajenoj map&#8217;u po klju\u010deve.<\/p>\n<p><\/p>\n<p>Drugi nedostatak je taj \u0161to je LevelDB napisan na C-u. Poziv C-funkcija iz Go-a nije jako brz. Traje stotine nanosekundi. To nije jako brzo, jer u usporedbi s obi\u010dnim pozivom funkcije napisane na Go-u, koja traje 1-5 nanosekundi, razlika u performansama je nekoliko desetaka puta. Za VictoriaMetrics, ovo 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>Zbog toga sam napisao vlastitu implementaciju invertiranog 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 je baziran na strukturi podataka MergeTree. Ova struktura podataka je preuzeta iz ClickHouse-a. O\u010digledno je da mergeset mora biti optimiziran za brzo pretra\u017eivanje <code>timeseries_ids<\/code> po zadanom klju\u010di. Mergeset je potpuno napisan na Go-u. Mo\u017eete pogledati <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">izvore VictoriaMetrics na GitHubu<\/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 shvatiti \u0161to se tamo doga\u0111a.<\/p>\n<p><\/p>\n<p>API mergeseta je vrlo sli\u010dan LevelDB-u i RocksDB-u. T. j. omogu\u0107ava brzo pohranjivanje novih zapisa i brzo biranje zapisa prema zadanom 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 razgovarati o problemima koji su nastali s VictoriaMetrics u produkciji prilikom implementacije invertiranog indeksa.<\/p>\n<p><\/p>\n<p>Za\u0161to su se pojavili?<\/p>\n<p><\/p>\n<p>Prvi razlog je visoka promjena podataka. U prijevodu na hrvatski \u2013 to je \u010desta promjena vremenskih serija. To se doga\u0111a kada vremenska serija zavr\u0161ava i po\u010dinje nova serija, ili po\u010dinju brojne nove vremenske serije. A to se doga\u0111a \u010desto.<\/p>\n<p><\/p>\n<p>Drugi razlog je veliki broj vremenskih serija. Na po\u010detku, kada je monitoring postajao sve popularniji, broj vremenskih serija bio je mali. Na primjer, za svaki ra\u010dunar treba pratiti optere\u0107enje procesora, memorije, mre\u017ee i diska. 4 vremenske serije po ra\u010dunalu. Imate, recimo, 100 ra\u010dunala i 400 vremenskih serija. To je jako malo. <\/p>\n<p><\/p>\n<p>S vremenom su ljudi smislili kako mjeriti detaljnije informacije. Na primjer, mjeriti optere\u0107enje ne cijelog procesora, nego posebno svakog procesorskog jezgra. Ako imate 40 procesorskih jezgri, tada imate 40 puta vi\u0161e vremenskih serija za mjerenje optere\u0107enja procesora. <\/p>\n<p><\/p>\n<p>No, to nije sve. Svako procesorsko jezgro mo\u017ee imati nekoliko stanja, kao \u0161to su idle, kada ne radi. Tako\u0111er, rad u user spaceu, rad u kernel spaceu i druga stanja. Svako takvo stanje tako\u0111er se mo\u017ee mjeriti kao zasebna vremenska serija. To dodatno pove\u0107ava broj serija 7-8 puta.<\/p>\n<p><\/p>\n<p>Iz jedne metrike dobivamo 40 x 8 = 320 metrika samo za jedno ra\u010dunalo. Pomno\u017eimo s 100, dobijemo 32 000 umjesto 400. <\/p>\n<p><\/p>\n<p>Kasnije je do\u0161ao Kubernetes. I ponovno je pogor\u0161ao situaciju, jer se u Kubernetesu mo\u017ee hostati mnogo razli\u010ditih servisa. Svaki servis u Kubernetesu sastoji se od mnogih podova. I sve to treba pratiti. Osim toga, imamo kontinuirani deployment novih verzija va\u0161ih servisa. Za svaku novu verziju trebamo kreirati nove vremenske serije. Na kraju se broj vremenskih serija eksponencijalno pove\u0107ava i suo\u010davamo se s problemom velikog broja vremenskih serija, \u0161to se naziva high-cardinality. VictoriaMetrics se s tim uspje\u0161no nosi u usporedbi s drugim bazama podataka za vremenske serije. <\/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>Pogledajmo detaljnije high churn rate. Za\u0161to se javi high churn rate u produkciji? Zbog toga \u0161to se neka vrijednosti oznaka i tagova stalno mijenjaju.<\/p>\n<p><\/p>\n<p>Na primjer, uzmimo Kubernetes, u kojem postoji pojam <code>deployment<\/code>, tj. kada se ispu\u0161ta nova verzija va\u0161e aplikacije. Razvija\u010di Kubernetesa su iz nekog razloga odlu\u010dili dodati id\u2019\u0161ku deployment&#8217;a u oznaku.<\/p>\n<p><\/p>\n<p>\u0160ta je dovelo do ovoga? Svakom novom deployment&#8217;u sve stare vremenske serije se prekidaju, a umesto njih po\u010dinju nove vremenske serije s novom vredno\u0161\u0107u oznake. <code>deployment_id<\/code>. Takvih serija mo\u017ee biti stotine tisu\u0107a, pa \u010dak i milijuni.<\/p>\n<p><\/p>\n<p>Va\u017ena zna\u010dajka svega ovoga je da se ukupni broj vremenskih serija pove\u0107ava, ali broj vremenskih serija koje su trenutno aktivne, na koje dolaze podaci, ostaje konstantan. Takvo stanje naziva se \u2013 high churn rate.<\/p>\n<p><\/p>\n<p>Glavni problem visoke stope izlaska je osigurati stalnu brzinu pretra\u017eivanja svih vremenskih serija za odre\u0111eni skup oznaka unutar odre\u0111enog vremenskog intervala. Obi\u010dno se radi o vremenskom intervalu od posljednjeg sata ili posljednjeg dana. <\/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 rije\u0161iti ovaj problem? Ovo je prva opcija. Razdvojiti obrnuti indeks na neovisne dijelove po vremenu. Drugim rije\u010dima, prolazi odre\u0111eni vremenski interval, prestajemo raditi s trenutnim obrnuto indeksom. Stvaramo novi obrnuti indeks. Prolazi jo\u0161 jedan vremenski interval, kreiramo jo\u0161 jedan i jo\u0161 jedan. <\/p>\n<p><\/p>\n<p>I pri odabiru iz tih obrnutih indeksa nalazimo skup obrnutih indeksa koji odgovaraju zadanom intervalu. Samim tim, biramo odatle ID-ove vremenskih serija. <\/p>\n<p><\/p>\n<p>To omogu\u0107uje u\u0161tedu resursa jer ne moramo pregledavati dijelove koji ne pripadaju zadanom intervalu. Drugim rije\u010dima, obi\u010dno, ako biramo podatke za posljednji sat, propu\u0161tamo zahtjeve 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 rje\u0161avanje ovog problema. To je da za svaki dan \u010duvamo zaseban popis ID-ova vremenskih serija koje su se pojavile tijekom tog dana.<\/p>\n<p><\/p>\n<p>Prednost ovog rje\u0161enja u odnosu na prethodno rje\u0161enje je u tome \u0161to ne dupliciramo informacije o vremenskim serijama koje ne nestaju tijekom vremena. One su stalno prisutne i ne mijenjaju se. <\/p>\n<p><\/p>\n<p>Nedostatak je u tome \u0161to je takvo rje\u0161enje slo\u017eenije za implementaciju i te\u017ee za ispravak. I VictoriaMetrics je odabrala ovo rje\u0161enje. Povijesno se tako dogodilo. Ovo rje\u0161enje tako\u0111er se pokazuje dobro u usporedbi s prethodnim. Jer ovo rje\u0161enje nije implementirano zbog potrebe za dupliciranjem podataka u svakom dijelu za vremenske serije koje se ne mijenjaju, odnosno koje ne nestaju tijekom vremena. VictoriaMetrics je prvenstveno optimizovana za potro\u0161nju diskovnog prostora, a prethodna implementacija pogor\u0161avala je potro\u0161nju diskovnog prostora. Ovo rje\u0161enje bolje odgovara minimiziranju potro\u0161nje diskovnog prostora, stoga je odabrano. <\/p>\n<p><\/p>\n<p>Morao sam se boriti s tim. Borba se sastojala u tome da se u ovoj implementaciji mora odabrati mnogo vi\u0161e podataka. <code>timeseries_ids<\/code> za podatke, nego kada je obrnuti indeks razdvojen po 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 rije\u0161ili ovaj problem? Rije\u0161ili smo ga na originalan na\u010din - tako da smo sa\u010duvali nekoliko identifikatora vremenskih serija u svakoj stavci invertiranog indeksa umjesto jednog identifikatora. To jest, imamo klju\u010d <code>label=value<\/code>, koji se pojavljuje u svakoj vremenskoj seriji. I sada \u010duvamo nekoliko <code>timeseries_ids<\/code> u jednoj stavci.<\/p>\n<p><\/p>\n<p>Evo primjera. Nekada smo imali N stavki, a sada imamo jednu stavku \u010diji je prefiks isti kao i kod svih ostalih. U prethodnoj stavci vrijednost sadr\u017ei sve id vremenskih serija. <\/p>\n<p><\/p>\n<p>To je omogu\u0107ilo pove\u0107anje brzine skeniranja takvog invertiranog indeksa do 10 puta. Tako\u0111er je smanjilo potro\u0161nju memorije za cache, jer sada \u010duvamo niz <code>label=value<\/code> samo jedanput u cacheu zajedno sa N puta. I taj niz mo\u017ee biti veliki, ako u oznakama i tagovima pohranjujete duga\u010dke redove koje Kubernetes rado ubacuje.<\/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>Jo\u0161 jedna opcija za ubrzanje pretra\u017eivanja kroz invertirani indeks je sharding. Kreiranje nekoliko invertiranih indeksa umjesto jednog i shardiranje podataka izme\u0111u njih po klju\u010du. To je skup <code>key=value<\/code> parova. To jest, dobijamo nekoliko neovisnih invertiranih indeksa koje mo\u017eemo paralelno ispitivati na nekoliko procesora. Prethodne implementacije omogu\u0107avale su rad samo u jednoj procesorskoj konfiguraciji, to jest skeniranje podataka samo na jednom jezgru. Ovo rje\u0161enje omogu\u0107ava skeniranje podataka istovremeno na nekoliko jezgri, ba\u0161 kao \u0161to to voli raditi ClickHouse. To planiramo implementirati.<\/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>A sada se vratimo na\u0161im ovnima - funkciji presijecanja <code>timeseries_ids<\/code>. Razmotrimo koje bi mogle biti implementacije. Ova funkcija omogu\u0107ava pronala\u017eenje <code>timeseries_ids<\/code> za zadani skup <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 opcija je naivna implementacija. Dva ugnije\u017edena ciklusa. Tako dobijamo ulaz za funkcije <code>intersectInts<\/code> dva slices \u2014 <code>a<\/code> i <code>b<\/code>. Na izlazu treba vratiti presjek ovih slices.<\/p>\n<p><\/p>\n<p>Naivna implementacija izgleda ovako. Prolazimo kroz sve vrijednosti iz slice <code>a<\/code>, unutar ovog ciklusa prolazimo kroz sve vrijednosti slice <code>b<\/code>. I uspore\u0111ujemo ih. Ako se poklapaju, tada smo prona\u0161li presjek. I spremamo ga u <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>Koje su nedostatke? Kvadratna slo\u017eenost - to je njen glavni nedostatak. Na primjer, ako imate veli\u010dine slice <code>a<\/code> i <code>b<\/code> Ako tra\u017eite milijun, ova funkcija nikada ne\u0107e dati odgovor. Jer \u0107e morati napraviti jedan trilijun iteracija, \u0161to je jako puno \u010dak i za moderne ra\u010dunare.<\/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 se temelji na map. Napravimo map. Stavimo sve vrijednosti iz slice u tu map. <code>a<\/code>. Zatim prolazimo kroz slice odvojenom petljom. <code>b<\/code>. I provjeravamo \u2013 postoji li ta vrijednost iz slice. <code>b<\/code> u mapi. Ako postoji, dodajemo je u rezultat. <\/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>Koje su prednosti? Prednost je u tome \u0161to ovdje postoji samo linearna slo\u017eenost. To jest, funkcija \u0107e se mnogo br\u017ee izvr\u0161iti za velike veli\u010dine slices. Za milijun veli\u010dinu slice, ova funkcija \u0107e se izvr\u0161iti za 2 milijuna iteracija, za razliku od trilijun iteracija, kao u prethodnoj funkciji.<\/p>\n<p><\/p>\n<p>A nedostatak je u tome \u0161to ova funkcija zahtijeva vi\u0161e memorije da bi se stvorila ova mapa.<\/p>\n<p><\/p>\n<p>Drugi nedostatak \u2013 to je veliki overhead za hashiranje. Ova mana nije toliko o\u010dita. I za nas to tako\u0111er nije bilo toliko o\u010dito, pa je u po\u010detku u VictoriaMetrics implementacija intersection bila putem mape. No, profiliranje je pokazalo da se najve\u0107e procesorsko vreme tro\u0161i na zapisivanje u mapu i na provjeru prisutnosti vrijednosti u toj mapi.<\/p>\n<p><\/p>\n<p>Za\u0161to se procesorsko vreme tro\u0161i na tim mjestima? Zato \u0161to u tim redovima Go provodi operaciju hashiranja. To jest, izra\u010dunava hash od klju\u010da da bi se zatim obratio po zadanom indeksu u HashMap. Operacija izra\u010dunavanja hasha se izvr\u0161ava za desetine nanosekundi. To je sporo za VictoriaMetrics.<\/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>Odlu\u010dio sam realizirati bitset, optimiziran posebno za ovaj slu\u010daj. Tako sada izgleda presjek dva slices. Ovdje stvaramo bitset. Dodajemo u njega elemente iz prvog slice. Zatim provjeravamo prisutnost tih elemenata u drugom slice. I dodajemo ih u rezultat. To jest, gotovo se ne razlikuje od prethodnog primjera. Jedina razlika je u tome \u0161to smo ovdje zamijenili pristup mapi s prilago\u0111enim funkcijama. <code>add<\/code> i <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 \u010dini se da bi to trebalo raditi sporije, ako je ranije kori\u0161tena standardna mapa, a ovdje se jo\u0161 pozivaju neke funkcije, ali profiliranje pokazuje da ova stvar radi 10 puta br\u017ee od standardne mape za slu\u010daj s VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Osim toga, koristi mnogo manje memorije u odnosu na implementaciju s mapom. Jer ovdje spremamo bitove umjesto osmobajtnih vrijednosti.<\/p>\n<p><\/p>\n<p>Nedostatak ove implementacije je u tome \u0161to nije tako o\u010digledna, nije trivijalna. <\/p>\n<p><\/p>\n<p>Jo\u0161 jedan nedostatak koji mnogi mo\u017eda ne\u0107e primijetiti je da ova implementacija mo\u017ee lo\u0161e raditi u nekim slu\u010dajevima. To jest, optimizirana je za specifi\u010dni slu\u010daj, za ovaj slu\u010daj preklapanja ids vremenskih serija VictoriaMetrics. To ne zna\u010di da \u0107e odgovarati svim slu\u010dajevima. Ako se ne koristi ispravno, mo\u017ee do\u0107i do nedostatka memorije i usporavanja performansi. <\/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>Razmotrite implementaciju ove strukture. Ako \u017eelite pogledati, nalazi se u izvorima VictoriaMetrics, u direktoriju <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/uint64set\">lib\/uint64set<\/a><\/noindex>. Optimizirana je upravo za slu\u010daj VictoriaMetrics, gdje <code>timeseries_id<\/code> predstavlja 64-bitnu vrijednost, pri \u010demu se prvih 32 bita u osnovi stalno, a samo se posljednjih 32 bita mijenjaju.<\/p>\n<p><\/p>\n<p>Ova struktura podataka ne pohranjuje se na disku, ve\u0107 radi samo u memoriji. <\/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>Evo njenog API-a. Nije previ\u0161e slo\u017een. API je prilago\u0111en konkretnoj primjer koristi VictoriaMetrics. To jest, ovdje nema suvi\u0161nih funkcija. Ovdje su funkcije koje se jasno koriste u VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Postoje funkcije <code>add<\/code>, koja dodaje nove vrijednosti. Postoji funkcija <code>has<\/code>, koja provjerava nove vrijednosti. A postoji funkcija <code>del<\/code>, koja uklanja vrijednosti. Tu je i pomo\u0107na funkcija <code>len<\/code>, koja vra\u0107a veli\u010dinu skupa. Funkcija <code>clone<\/code> klonira skup. I funkcija <code>appendto<\/code> pretvara ovaj skup u 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>Ovako izgleda implementacija ove strukture podataka. U skupu su dva elementa:<\/p>\n<p><\/p>\n<ul>\n<li>\n<p><code>ItemsCount<\/code> \u2013 to je pomo\u0107no polje koje omogu\u0107ava brzo vra\u0107anje broja elemenata u skupu. Mogli bismo pro\u0107i bez ovog pomo\u0107nog polja, ali je morali dodati ovdje jer VictoriaMetrics \u010desto provjerava duljinu bitseta u svojim algoritmima.<\/p>\n<p>\n<\/li>\n<li>\n<p>Drugo polje je <code>buckets<\/code>. To je slice strukture <code>bucket32<\/code>. U svakoj strukturi pohranjuje se <code>hi<\/code> polje. To su gornjih 32 bita. I dva slice \u2014 <code>b16his<\/code> i <code>buckets<\/code> iz <code>bucket16<\/code> struktura. <\/p>\n<p>\n<\/li>\n<\/ul>\n<p><\/p>\n<p>Ovdje su pohranjeni gornjih 16 bita druge polovice 64-bitne strukture. A ovdje su bitsetovi za ni\u017eih 16 bita svakog bajta. <\/p>\n<p><\/p>\n<p><code>Bucket64<\/code> se sastoji od niza <code>uint64<\/code>. Duljina se izra\u010dunava pomo\u0107u ovih konstanti. U jednom <code>bucket16<\/code> maksimum mo\u017ee pohranjivati <code>2^16=65536<\/code> bita. Ako podijelimo s 8, to je 8 kilobajta. Ako podijelimo ponovno s 8, to je 1000 <code>uint64<\/code> vrijednosti. To jest, <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>Pogledajmo kako je implementirana jedna od metoda ove strukture za dodavanje nove vrijednosti. <\/p>\n<p><\/p>\n<p>Sve zapo\u010dinje s <code>uint64<\/code> vrijednosti. Izra\u010dunavamo gornjih 32 bita, izra\u010dunavamo donjih 32 bita. Prolazimo kroz sve <code>buckets<\/code>. Uspore\u0111ujemo gornjih 32 bita u svakom bucket-u s dodanom vrijedno\u0161\u0107u. Ako se poklapaju, pozivamo funkciju <code>add<\/code> u strukturi b32 <code>buckets<\/code>. I dodajemo donjih 32 bita. Ako to vrati <code>true<\/code>, to zna\u010di da smo dodali takvu vrijednost i da je nismo imali. Ako vra\u0107a <code>false<\/code>, tada je takva vrijednost ve\u0107 bila. Zatim pove\u0107avamo broj elemenata u strukturi. <\/p>\n<p><\/p>\n<p>Ako nismo prona\u0161li odgovaraju\u0107i <code>bucket<\/code> s potrebnom hi-vrijedno\u0161\u0107u, pozivamo funkciju <code>addAlloc<\/code>, koja dodjeljuje novi <code>bucket<\/code>, dodaju\u0107i ga u bucket-strukturu.<\/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>To 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 gornje 16 bita. Pronalazimo podudaranja. U slu\u010daju podudaranja pozivamo metodu add, koju \u0107emo razmotriti na sljede\u0107oj stranici 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\u017ea razina koja bi trebala biti maksimalno optimizirana. Izra\u010dunavamo za <code>uint64<\/code> id vrijednost u slice bitu, kao i <code>bitmask<\/code>. Ovo je maska za ovu 64-bitnu vrijednost, kojom se mo\u017ee provjeriti postojanje ovog bita ili ga postaviti. Provjeravamo postojanje ovog bita, postavljamo ga i vra\u0107amo njegovo postojanje. Ova implementacija nam je omogu\u0107ila da ubrzamo operaciju preklapanja ids vremenskih serija 10 puta u odnosu na obi\u010dne mape.<\/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 tih optimizacija nije dodana tek tako, ve\u0107 nakon profiliranja koda u produkciji.<\/p>\n<p><\/p>\n<p>To je glavno pravilo optimizacije \u2013 ne dodavati optimizaciju pretpostavljaju\u0107i da \u0107e ovdje biti usko grlo, jer se mo\u017ee pokazati da ne\u0107e biti uskog grla. Optimizacija obi\u010dno pogor\u0161ava kvalitetu koda. Stoga bi trebalo optimizirati samo nakon profiliranja i po mogu\u0107stvu u produkciji, kako bi to bili stvarni podaci. Tko je zainteresiran, mo\u017ee pogledati izvorne kodove VictoriaMetrics i prou\u010diti druge optimizacije koje postoje.<\/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 bitsetu. Jako podsje\u0107a na implementaciju C++ vector bool, optimizirani bitset. Jeste li uzeli implementaciju odatle?<\/em><\/p>\n<p><\/p>\n<p>Ne, to nije izvor. Prilikom implementacije ovog bitset-a, orijentirao sam se na znanje strukture ovih ids vremenskih serija koje se koriste u VictoriaMetrics. Njihova struktura je takva da je gornjih 32 bita uglavnom stalno. Donjih 32 bita se mogu mijenjati. \u0160to je ni\u017ei bit, to se \u010de\u0161\u0107e mo\u017ee mijenjati. Stoga je ova implementacija optimizirana upravo za ovu strukturu podataka. C++ implementacija, koliko znam, optimizirana je za op\u0107i slu\u010daj. Ako se radi optimizacija za op\u0107i slu\u010daj, to zna\u010di da ne\u0107e biti najoptimalnija za konkretni slu\u010daj.<\/p>\n<p><\/p>\n<p>Preporu\u010dujem vam da jo\u0161 pogledate izlaganje Alekseja Milovida. Prije otprilike mjesec dana govorio je o optimizacijama u ClickHouse-u za konkretne specijalizacije. On ba\u0161 obja\u0161njava da su u op\u0107em slu\u010daju C++ implementacija ili neka druga implementacija prilago\u0111ene za dobar rad u prosjeku. Mogu raditi lo\u0161ije od specijalizirane implementacije koja se temelji na konkretnim saznanjima, kao kod nas, kada znamo da su gornji 32 bita uglavnom stalni.<\/p>\n<p><\/p>\n<p><em>Imam drugo pitanje. Koja su kardinalna razlikovanja od InfluxDB-a?<\/em><\/p>\n<p><\/p>\n<p>Postoji mnogo kardinalnih razlika. \u0160to se ti\u010de performansi i potro\u0161nje memorije, InfluxDB u testovima pokazuje 10 puta ve\u0107u potro\u0161nju memorije za vremenske serije visoke kardinalnosti, kada ih imate puno, na primjer, milijune. Na primjer, VictoriaMetrics tro\u0161i 1 GB na milijun aktivnih serija, dok InfluxDB tro\u0161i 10 GB. I to je velika razlika. <\/p>\n<p><\/p>\n<p>Druga kardinalna razlika je u tome \u0161to InfluxDB ima \u010dudne jezike upita \u2013 Flux i InfluxQL. Nisu ba\u0161 zgodni za rad s vremenskim serijama u usporedbi s <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@valyala\/promql-tutorial-for-beginners-9ab455142085\">PromQL<\/a><\/noindex>, koji se podr\u017eava u VictoriaMetrics-u. PromQL \u2013 jezik upita iz Prometheusa.<\/p>\n<p><\/p>\n<p>I jo\u0161 jedna razlika je ta da InfluxDB ima pomalo neobi\u010dan model podataka, gdje u svakom retku mo\u017ee biti pohranjeno nekoliko polja s razli\u010ditim skupovima oznaka. Ti redovi se dijele na razne tablice. Ova dodatna slo\u017eenja ote\u017eavaju daljnji rad s ovom bazom. Te\u0161ko je odr\u017eavati i razumjeti.<\/p>\n<p><\/p>\n<p>U VictoriaMetrics-u je sve puno jednostavnije. Tamo svaka vremenska serija predstavlja klju\u010d-vrijednost. Vrijednost \u2013 to je skup to\u010daka \u2013 <code>(timestamp, value)<\/code>, a klju\u010d \u2013 to je skup <code>label=value<\/code>. Nema podjele na fields i measurements. To vam omogu\u0107uje da birate bilo koje podatke, a zatim ih kombinirate, zbrajate, oduzimate, mno\u017eite i dijelite, za razliku od InfluxDB-a gdje izra\u010duni izme\u0111u razli\u010ditih redaka jo\u0161 uvijek nisu implementirani, koliko ja znam. \u010cak i ako su implementirani, to je te\u0161ko, potrebno je napisati puno koda. <\/p>\n<p><\/p>\n<p><em>Imam dodatno pitanje. Jesam li dobro shvatio da je postojala neka pote\u0161ko\u0107a koju ste spominjali, da taj obrnuti indeks ne stane u memoriju, pa se podaci dijele?<\/em><\/p>\n<p><\/p>\n<p>Na po\u010detku sam prikazao naivnu implementaciju inverted index-a na standardnoj Go&#8217;\u0161noj map&#8217;i. Ova implementacija nije pogodna za baze podataka jer se ovaj inverted index ne \u010duva na disku, a baza podataka mora \u010duvati podatke na disku kako bi bili dostupni nakon ponovnog pokretanja. U ovoj implementaciji, prilikom ponovnog pokretanja aplikacije, va\u0161 inverted index \u0107e nestati. I izgubi\u0107ete pristup svim podacima jer ih ne\u0107ete mo\u0107i prona\u0107i. <\/p>\n<p><\/p>\n<p><em>Pozdrav! Hvala na izlaganju! Zovem se Pavel. Dolazim iz kompanije Wildberries. Imam nekoliko pitanja za vas. Prvo pitanje. Kako vam se \u010dini, da ste izabrali drugi princip pri gra\u0111enju arhitekture svoje aplikacije i partijonirali podatke prema vremenu, mo\u017eda biste mogli raditi presjek podataka pri pretra\u017eivanju, temeljen samo na tome da se u jednoj particiji nalaze podaci za jedan vremenski interval, tj. da ne biste morali brinuti o razbacanim dijelovima? Pitanje broj 2 \u2014 budu\u0107i da implementirate sli\u010dan algoritam s bitset-om i svim ostalim, jeste li mo\u017eda poku\u0161ali koristiti procesorske instrukcije? Mo\u017eda ste isprobali takve optimizacije?<\/em><\/p>\n<p><\/p>\n<p>Na drugo odmah odgovaram. Nismo jo\u0161 stigli do toga. Ali ako bude potrebno, do\u0107i \u0107emo. A koje je bilo prvo pitanje?<\/p>\n<p><\/p>\n<p><em>Raspravili ste o dva scenarija. I rekli ste da ste izabrali drugi s slo\u017eenijom implementacijom. I niste preferirali prvi, gdje su podaci podijeljeni prema vremenu.<\/em> <\/p>\n<p><\/p>\n<p>Da. U prvom slu\u010daju ukupna koli\u010dina indeksa bi bila ve\u0107a, jer bismo u svakoj particiji morali \u010duvati duplikate podataka za one vremenske serije koje se prote\u017eu kroz sve te particije. I ako je va\u0161 churn rate za vremenske serije mali, tj. ako se stalno koriste iste serije, u prvom slu\u010daju bismo znatno vi\u0161e izgubili u koli\u010dini zauzetog diskovnog prostora u odnosu na drugi slu\u010daj.<\/p>\n<p><\/p>\n<p>Ali da, vremensko particioniranje je dobra opcija. To koristi i Prometheus. No, Prometheus ima jo\u0161 jedan nedostatak. Kada spaja te delove podataka, treba zadr\u017eati u memoriji meta-informacije o svim labelima i vremenskim serijama. Stoga, ako su delovi podataka veliki koje spaja, potro\u0161nja memorije znatno raste tokom spajanja, za razliku od VictoriaMetrics. Tokom spajanja, VictoriaMetrics uop\u0107e ne tro\u0161i memoriju, potro\u0161i nekoliko kilobajta, bez obzira na veli\u010dinu spajanih delova podataka.<\/p>\n<p><\/p>\n<p><em>Algoritam koji koristite koristi memoriju. U njoj se bele\u017ee oznake vremenskih serija koje imaju vrednosti. Tako proveravate prisutnost u jednom i drugom skupu podataka. I shvatate da li je do\u0161lo do preseka ili ne. Obi\u010dno se u bazama podataka implementiraju kursori, iteratori, koji \u010duvaju svoje trenutno stanje i prolaze kroz sortirane podatke, zbog \u010dega imate jednostavnu slo\u017eenost tih operacija.<\/em> <\/p>\n<p><\/p>\n<p>Za\u0161to ne koristimo kursor za presek podataka?<\/p>\n<p><\/p>\n<p><em>Da.<\/em> <\/p>\n<p><\/p>\n<p>U na\u0161em LevelDB ili u mergesetu \u010duvaju se sortirani redovi. Mo\u017eemo pro\u0107i kursorom i prona\u0107i presek. A za\u0161to ne koristimo? Zato \u0161to je sporo. Zato \u0161to kursori podrazumevaju da se za svaki red mora pozvati funkcija. Poziv funkcije traje 5 nanosekundi. A ako imate 100 000 000 redova, dobijate da tro\u0161imo pol sekunde samo na poziv funkcije.<\/p>\n<p><\/p>\n<p><em>To postoji, da. I poslednje moje pitanje. Pitanje koje mo\u017eda zvu\u010di malo \u010dudno. Za\u0161to se u trenutku prijema podataka ne mogu izra\u010dunati svi potrebni agregati i sa\u010duvati ih u potrebnom obliku? Za\u0161to \u010duvati ogromne koli\u010dine u sistemima poput VictoriaMetrics, ClickHouse itd., da bi kasnije tro\u0161ili mnogo vremena na njih?<\/em><\/p>\n<p><\/p>\n<p><em>Dat \u0107u primjer da bude jasnije. Recimo, kako radi mali igra\u010dka brzinomjer? On bilje\u017ei udaljenost koju ste pre\u0161li, stalno je dodaju\u0107i u jedan iznos, a u drugi \u2013 vrijeme. I dijeli. I dobije prosje\u010dnu brzinu. Mo\u017eemo u\u010diniti otprilike isto. Zbrajati u hodu sve potrebne \u010dinjenice.<\/em><\/p>\n<p><\/p>\n<p>Dobro, razumijem pitanje. Va\u0161 primjer ima smisla. Ako znate koje su vam potrebne agregate, to je najbolja implementacija. No, problem je u tome \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 ga ne biste izra\u010dunali, umjesto da ondje pohranjujete hrpu sirovih vrijednosti? Ali to samo ako znate \u0161to vam to\u010dno 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 napraviti ako znate koji su vam potrebni agregati. U VictoriaMetrics toga trenutno nema, ali ispred nje obi\u010dno se stavlja Prometheus, u kojem to mo\u017eete u\u010diniti u pravilima snimanja.<\/p>\n<p><\/p>\n<p>Na primjer, na prethodnom poslu trebalo je brojati broj doga\u0111aja u pomi\u010dnom prozoru u zadnjem satu. Problem je bio u tome \u0161to je trebalo napraviti prilago\u0111enu implementaciju na Go, tj. servis za brojanje te stvari. Taj servis na kraju nije bio trivijalan, jer je te\u0161ko ra\u010dunati. Implementacija mo\u017ee biti jednostavna ako trebate brojati neke agregate na fiksnim vremenskim intervalima. Me\u0111utim, ako \u017eelite brojati doga\u0111aje u pomi\u010dnom prozoru, to nije tako jednostavno kao \u0161to izgleda. Mislim da to jo\u0161 uvijek nije implementirano u ClickHouse ili u bazama vremenskih serija, jer je to te\u0161ko za implementaciju.<\/p>\n<p><\/p>\n<p><em>I jo\u0161 jedno pitanje. Sada smo govorili o prosje\u010denju, i sjetio sam se da je nekad postojala stvar kao \u0161to je Graphite s backendom Carbon. I on je znao prorijediti stare podatke, tj. ostaviti jednu to\u010dku u minuti, jednu to\u010dku na satu itd. U principu, to je prili\u010dno zgodno, ako nam trebaju sirovi podaci, uvjetno re\u010deno, za mjesec dana, a sve ostalo se mo\u017ee prorijediti. No, Prometheus i VictoriaMetrics ne podr\u017eavaju tu funkcionalnost. Planira li se podr\u017eavati? Ako ne, za\u0161to?<\/em><\/p>\n<p><\/p>\n<p>Hvala na pitanju. Na\u0161i korisnici nas to povremeno pitaju. Pitaju kada \u0107emo dodati podr\u0161ku za downsampling. Ovdje se pojavljuje nekoliko problema. Prvo, svaki korisnik pod <code>downsampling<\/code> razumije ne\u0161to drugo: netko \u017eeli dobiti bilo koju to\u010dku na zadanom intervalu, netko \u017eeli maksimalne, minimalne, prosje\u010dne vrijednosti. Ako va\u0161a baza podataka prima podatke iz vi\u0161e sustava, ne mo\u017eete ih sve razdvojiti. Mo\u017ee se dogoditi da za svaki sustav treba koristiti razli\u010dito prorje\u0111ivanje. I to je te\u0161ko za implementirati.<\/p>\n<p><\/p>\n<p>Drugo je to da je VictoriaMetrics, kao i ClickHouse, optimizirana za rad s velikim koli\u010dinama sirovih podataka, stoga mo\u017ee obraditi milijardu redaka za manje od sekunde, ako imate mnogo jezgri u va\u0161em sustavu. Skeniranje to\u010daka vremenskih serija u VictoriaMetrics iznosi 50 000 000 to\u010daka u sekundi po jednoj jezgri. I ta se izvedba skalira na dostupne jezgre. Drugim rije\u010dima, ako imate 20 jadra, na primjer, mo\u017ee se skenirati milijardu to\u010daka u sekundi. Ova osobina VictoriaMetrics i ClickHouse smanjuje potrebu za downsamplingom.<\/p>\n<p><\/p>\n<p>Jo\u0161 jedna osobina je da VictoriaMetrics u\u010dinkovito komprimira te podatke. Kompresija u prosjeku na produkciji iznosi od 0,4 do 0,8 bajta po to\u010dki. Svaka to\u010dka je timestamp + vrijednost. I ona se komprimira na manje od jednog bajta u prosjeku. <\/p>\n<p><\/p>\n<p><em>Sergej. Imamo pitanje. Kolika je minimalna granica vremena zapisivanja?<\/em><\/p>\n<p><\/p>\n<p>Jedna milisekunda. Nedavno smo razgovarali s drugim programerima baza podataka za vremenske serije. Njihova minimalna granica vremena je jedna sekunda. U Graphiteu, na primjer, tako\u0111er je jedna sekunda. U OpenTSDB tako\u0111er je jedna sekunda. U InfluxDB \u2013 nanosjekundna preciznost. U VictoriaMetrics \u2013 jedna milisekunda, jer u Prometheusu imamo jednu milisekundu. I VictoriaMetrics je prvotno razvijena kao udaljeni spremnik za Prometheus. No sada mo\u017ee \u010duvati podatke i iz drugih sustava. <\/p>\n<p><\/p>\n<p>Osoba s kojom sam razgovarao ka\u017ee da imaju sekundarnu preciznost \u2014 to im je dovoljno, jer ovisi o vrsti podataka koji se spremaju u bazu vremenskih serija. Ako su to DevOps podaci ili podaci s infrastrukture, gdje ih prikupljate u intervalima od 30 sekundi do jedne minute, tada je sekundna preciznost dovoljna, manje ne treba. No ako prikupljate te podatke iz sustava s visokom frekvencijom trgovanja, tada je potrebna nanosjekundna preciznost.<\/p>\n<p><\/p>\n<p>Millisekundna preciznost u VictoriaMetrics pogodna je i za DevOps slu\u010dajeve, i mo\u017ee odgovarati ve\u0107ini slu\u010dajeva koje sam spomenuo na po\u010detku izlaganja. Jedino za \u0161to mo\u017eda ne\u0107e biti prikladna su sustavi za visoko frekventno trgovanje.<\/p>\n<p><\/p>\n<p><em>Hvala! I jo\u0161 jedno pitanje. Koja je kompatibilnost u PromQL?<\/em><\/p>\n<p><\/p>\n<p>Potpuna unazadna kompatibilnost. VictoriaMetrics potpuno podr\u017eava PromQL. Osim toga, dodaje jo\u0161 dodatnu pro\u0161irenu funkcionalnost na PromQL koja se zove <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/wiki\/MetricsQL\">MetricsQL<\/a><\/noindex>. \u0160to se ti\u010de te pro\u0161irene funkcionalnosti, postoji izlaganje na YouTubeu. Govorio sam o tome na Monitoring Meetup-u u prolje\u0107e u 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 registrirani korisnici mogu sudjelovati u anketi. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Prijavite se<\/a><\/noindex>, molimo.<\/p>\n<h2 class=\"default-block__polling-title\">\u0160to vas spre\u010dava da pre\u0111ete na VictoriaMetrics kao dugotrajno skladi\u0161te za Prometheus? (Napi\u0161ite u komentarima, dodati \u0107u 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. Suzdr\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\/hr\/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=\"hr_HR\" \/>\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\/hr\/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\udd47Optimizacije za Go u VictoriaMetrics. Aleksandar Valjaljin | ProHoster","description":"Predla\u017eem da se upoznate s transkriptom prezentacije Alexandra Valjaljkina \"Optimizacije Go u VictoriaMetrics\" s kraja 2019. godine","canonical_url":"https:\/\/prohoster.info\/hr\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"hr_HR","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\/hr\/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\/hr\/wp-json\/wp\/v2\/posts\/80733","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/comments?post=80733"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/posts\/80733\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media\/80734"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/media?parent=80733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/categories?post=80733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/hr\/wp-json\/wp\/v2\/tags?post=80733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}