Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Iminumungkahi kong basahin mo ang transcript ng huling 2019 na ulat ni Alexander Valyalkin "Go optimizations in VictoriaMetrics"

VictoriaMetrics β€” isang mabilis at nasusukat na DBMS para sa pag-iimbak at pagproseso ng data sa anyo ng isang serye ng oras (ang talaan ay bumubuo ng oras at isang hanay ng mga halaga na tumutugma sa oras na ito, halimbawa, nakuha sa pamamagitan ng pana-panahong pagboto ng katayuan ng mga sensor o koleksyon ng sukatan).

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Narito ang isang link sa video ng ulat na ito - https://youtu.be/MZ5P21j_HLE

Mga slide

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Sabihin sa amin ang tungkol sa iyong sarili. Ako si Alexander Valyalkin. Dito ang aking GitHub account. Mahilig ako sa Go at pag-optimize ng performance. Sumulat ako ng maraming kapaki-pakinabang at hindi masyadong kapaki-pakinabang na mga aklatan. Magsisimula sila sa alinman fast, o kasama quick unlapi.

Kasalukuyan akong nagtatrabaho sa VictoriaMetrics. Ano ito at ano ang ginagawa ko doon? Pag-uusapan ko ito sa presentasyong ito.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ang balangkas ng ulat ay ang mga sumusunod:

  • Una, sasabihin ko sa iyo kung ano ang VictoriaMetrics.
  • Pagkatapos ay sasabihin ko sa iyo kung ano ang mga serye ng oras.
  • Pagkatapos ay sasabihin ko sa iyo kung paano gumagana ang isang database ng serye ng oras.
  • Susunod, sasabihin ko sa iyo ang tungkol sa arkitektura ng database: kung ano ang binubuo nito.
  • At pagkatapos ay lumipat tayo sa mga pag-optimize na mayroon ang VictoriaMetrics. Isa itong optimization para sa inverted index at isang optimization para sa bitset na pagpapatupad sa Go.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

May nakakaalam ba sa audience kung ano ang VictoriaMetrics? Wow, marami na ang nakakaalam. Ito ay isang magandang balita. Para sa mga hindi nakakaalam, ito ay isang database ng serye ng oras. Ito ay batay sa arkitektura ng ClickHouse, sa ilang mga detalye ng pagpapatupad ng ClickHouse. Halimbawa, sa tulad ng: MergeTree, parallel na pagkalkula sa lahat ng magagamit na mga core ng processor at pag-optimize ng pagganap sa pamamagitan ng paggawa sa mga bloke ng data na inilalagay sa cache ng processor.

Nagbibigay ang VictoriaMetrics ng mas mahusay na compression ng data kaysa sa iba pang mga database ng time series.

Naka-scale ito nang patayo - iyon ay, maaari kang magdagdag ng higit pang mga processor, higit pang RAM sa isang computer. Matagumpay na magagamit ng VictoriaMetrics ang mga magagamit na mapagkukunang ito at mapapabuti ang linear na produktibidad.

Ang VictoriaMetrics ay sumusukat din nang pahalang - iyon ay, maaari kang magdagdag ng mga karagdagang node sa VictoriaMetrics cluster, at ang pagganap nito ay tataas nang halos linearly.

Gaya ng nahulaan mo, ang VictoriaMetrics ay isang mabilis na database, dahil hindi ako makapagsulat ng iba. At ito ay nakasulat sa Go, kaya pinag-uusapan ko ito sa meetup na ito.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Sino ang nakakaalam kung ano ang isang serye ng oras? Marami rin siyang kakilala. Ang isang serye ng oras ay isang serye ng mga pares (timestamp, Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅), kung saan ang mga pares na ito ay pinagbubukod-bukod ayon sa oras. Ang value ay isang floating point number – float64.

Ang bawat serye ng oras ay natatangi sa pamamagitan ng isang susi. Ano ang binubuo ng susi na ito? Binubuo ito ng isang walang laman na hanay ng mga pares ng key-value.

Narito ang isang halimbawa ng isang serye ng oras. Ang susi ng seryeng ito ay isang listahan ng mga pares: __name__="cpu_usage" ay ang pangalan ng sukatan, instance="my-server" - ito ang computer kung saan kinokolekta ang sukatang ito, datacenter="us-east" - ito ang data center kung saan matatagpuan ang computer na ito.

Natapos namin ang isang pangalan ng time series na binubuo ng tatlong pares ng key-value. Ang key na ito ay tumutugma sa isang listahan ng mga pares (timestamp, value). t1, t3, t3, ..., tN - ito ang mga timestamp, 10, 20, 12, ..., 15 β€” ang kaukulang mga halaga. Ito ang cpu-usage sa isang partikular na oras para sa isang partikular na serye.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Saan maaaring gamitin ang time series? Mayroon bang may ideya?

  • Sa DevOps, maaari mong sukatin ang CPU, RAM, network, rps, bilang ng mga error, atbp.
  • IoT - masusukat natin ang temperatura, presyon, geo coordinates at iba pa.
  • Gayundin sa pananalapi - maaari naming subaybayan ang mga presyo para sa lahat ng uri ng mga stock at pera.
  • Bilang karagdagan, ang mga serye ng oras ay maaaring gamitin sa pagsubaybay sa mga proseso ng produksyon sa mga pabrika. Mayroon kaming mga user na gumagamit ng VictoriaMetrics upang subaybayan ang mga wind turbine, para sa mga robot.
  • Kapaki-pakinabang din ang serye ng oras para sa pagkolekta ng impormasyon mula sa mga sensor ng iba't ibang device. Halimbawa, para sa isang makina; para sa pagsukat ng presyon ng gulong; para sa pagsukat ng bilis, distansya; para sa pagsukat ng pagkonsumo ng gasolina, atbp.
  • Ang serye ng oras ay maaari ding gamitin upang subaybayan ang sasakyang panghimpapawid. Ang bawat sasakyang panghimpapawid ay may isang itim na kahon na nangongolekta ng mga serye ng oras para sa iba't ibang mga parameter ng kalusugan ng sasakyang panghimpapawid. Ginagamit din ang serye ng oras sa industriya ng aerospace.
  • Ang pangangalaga sa kalusugan ay presyon ng dugo, pulso, atbp.

Maaaring may higit pang mga application na nakalimutan ko, ngunit inaasahan kong maunawaan mo na ang mga serye ng oras ay aktibong ginagamit sa modernong mundo. At ang dami ng kanilang paggamit ay lumalaki bawat taon.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Bakit kailangan mo ng database ng serye ng oras? Bakit hindi ka gumamit ng regular na relational database upang mag-imbak ng serye ng oras?

Dahil ang mga serye ng oras ay karaniwang naglalaman ng isang malaking halaga ng impormasyon, na mahirap iimbak at iproseso sa mga maginoo na database. Samakatuwid, lumitaw ang mga dalubhasang database para sa serye ng oras. Ang mga base na ito ay epektibong nag-iimbak ng mga puntos (timestamp, value) kasama ang ibinigay na susi. Nagbibigay ang mga ito ng API para sa pagbabasa ng nakaimbak na data sa pamamagitan ng key, sa pamamagitan ng isang pares ng key-value, o ng maraming pares ng key-value, o ng regexp. Halimbawa, gusto mong mahanap ang CPU load ng lahat ng iyong serbisyo sa isang data center sa America, pagkatapos ay kailangan mong gamitin ang pseudo-query na ito.

Karaniwang nagbibigay ang mga database ng time series ng mga espesyal na wika ng query dahil hindi masyadong angkop ang time series SQL. Bagama't may mga database na sumusuporta sa SQL, hindi ito masyadong angkop. Mga wika ng query tulad ng PromQL, InfluxQL, Pagkilos ng bagay, Q. Umaasa ako na may nakarinig ng kahit isa sa mga wikang ito. Marahil maraming tao ang nakarinig tungkol sa PromQL. Ito ang Prometheus query language.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ito ang hitsura ng modernong arkitektura ng database ng serye ng oras gamit ang VictoriaMetrics bilang isang halimbawa.

Ito ay binubuo ng dalawang bahagi. Ito ay storage para sa inverted index at storage para sa mga value ng time series. Ang mga repositoryo na ito ay pinaghihiwalay.

Kapag may bagong record na dumating sa database, ina-access muna namin ang inverted index para mahanap ang time series identifier para sa isang naibigay na set label=value para sa isang ibinigay na sukatan. Nahanap namin ang identifier na ito at i-save ang halaga sa data store.

Kapag dumating ang isang kahilingan upang kunin ang data mula sa TSDB, pupunta muna tayo sa inverted index. Kunin natin ang lahat timeseries_ids mga tala na tumutugma sa set na ito label=value. At pagkatapos ay nakukuha namin ang lahat ng kinakailangang data mula sa data warehouse, na na-index ng timeseries_ids.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Tingnan natin ang isang halimbawa kung paano pinoproseso ng database ng time series ang isang papasok na piling query.

  • Una sa lahat nakukuha niya ang lahat timeseries_ids mula sa isang baligtad na index na naglalaman ng mga ibinigay na pares label=value, o masiyahan ang isang ibinigay na regular na expression.
  • Pagkatapos ay kinukuha nito ang lahat ng mga punto ng data mula sa imbakan ng data sa isang naibigay na agwat ng oras para sa mga natagpuan timeseries_ids.
  • Pagkatapos nito, nagsasagawa ang database ng ilang kalkulasyon sa mga punto ng data na ito, ayon sa kahilingan ng user. At pagkatapos nito ay ibinalik nito ang sagot.

Sa pagtatanghal na ito sasabihin ko sa iyo ang tungkol sa unang bahagi. Ito ay isang paghahanap timeseries_ids sa pamamagitan ng inverted index. Maaari mong panoorin ang tungkol sa ikalawang bahagi at ang ikatlong bahagi mamaya Mga mapagkukunan ng VictoriaMetrics, o maghintay hanggang sa maghanda ako ng iba pang mga ulat :)

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Lumipat tayo sa baligtad na index. Maaaring isipin ng marami na ito ay simple. Sino ang nakakaalam kung ano ang isang baligtad na index at kung paano ito gumagana? Ay, wala na masyadong tao. Subukan nating maunawaan kung ano ito.

Ito ay talagang simple. Isa lang itong diksyunaryo na nagmamapa ng susi sa isang halaga. Ano ang isang susi? Itong mag-asawa label=valueSaan label ΠΈ value - ito ay mga linya. At ang mga halaga ay isang set timeseries_ids, na kinabibilangan ng ibinigay na pares label=value.

Binibigyang-daan ka ng inverted index na mabilis na mahanap ang lahat timeseries_ids, na nagbigay label=value.

Ito rin ay nagbibigay-daan sa iyo upang mabilis na mahanap timeseries_ids time series para sa ilang pares label=value, o para sa mga mag-asawa label=regexp. Paano ito nangyayari? Sa pamamagitan ng paghahanap ng intersection ng set timeseries_ids para sa bawat pares label=value.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Tingnan natin ang iba't ibang mga pagpapatupad ng inverted index. Magsimula tayo sa pinakasimpleng walang muwang na pagpapatupad. Parang ganito siya.

Tungkulin getMetricIDs nakakakuha ng listahan ng mga string. Ang bawat linya ay naglalaman ng label=value. Ang function na ito ay nagbabalik ng isang listahan metricIDs.

Paano ito gumagana? Dito mayroon tayong pandaigdigang variable na tinatawag invertedIndex. Ito ay isang regular na diksyunaryo (map), na magmamapa ng string upang hatiin ang mga ints. Ang linya ay naglalaman ng label=value.

Pagpapatupad ng function: get metricIDs para sa una label=value, pagkatapos ay dinadaanan namin ang lahat ng iba pa label=value, nakuha namin ito metricIDs para sa kanila. At tawagan ang function intersectInts, na tatalakayin sa ibaba. At ibinabalik ng function na ito ang intersection ng mga listahang ito.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Tulad ng nakikita mo, ang pagpapatupad ng isang baligtad na index ay hindi masyadong kumplikado. Ngunit ito ay isang walang muwang na pagpapatupad. Ano ang mga disadvantages mayroon ito? Ang pangunahing kawalan ng walang muwang na pagpapatupad ay ang naturang inverted index ay nakaimbak sa RAM. Pagkatapos i-restart ang application nawala namin ang index na ito. Walang pag-save ng index na ito sa disk. Ang nasabing isang baligtad na index ay malamang na hindi angkop para sa isang database.

Ang pangalawang disbentaha ay nauugnay din sa memorya. Ang inverted index ay dapat magkasya sa RAM. Kung ito ay lumampas sa laki ng RAM, pagkatapos ay malinaw naman na makukuha natin - mula sa error sa memorya. At ang programa ay hindi gagana.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ang problemang ito ay maaaring malutas gamit ang mga handa na solusyon tulad ng LevelDBO RocksDB.

Sa madaling salita, kailangan namin ng database na nagbibigay-daan sa amin na gawin ang tatlong operasyon nang mabilis.

  • Ang unang operasyon ay ang pagre-record ΠΊΠ»ΡŽΡ‡-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ sa database na ito. Ginagawa niya ito nang napakabilis, kung saan ΠΊΠ»ΡŽΡ‡-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ay mga arbitrary string.
  • Ang pangalawang operasyon ay isang mabilis na paghahanap para sa isang halaga gamit ang isang ibinigay na key.
  • At ang ikatlong operasyon ay isang mabilis na paghahanap para sa lahat ng mga halaga sa pamamagitan ng isang ibinigay na prefix.

LevelDB at RocksDB - ang mga database na ito ay binuo ng Google at Facebook. Unang dumating ang LevelDB. Pagkatapos ay kinuha ng mga lalaki mula sa Facebook ang LevelDB at sinimulan itong pahusayin, gumawa sila ng RocksDB. Ngayon halos lahat ng panloob na database ay gumagana sa RocksDB sa loob ng Facebook, kabilang ang mga nailipat sa RocksDB at MySQL. Pinangalanan nila siya MyRocks.

Maaaring ipatupad ang isang baligtad na index gamit ang LevelDB. Paano ito gagawin? Nagse-save kami bilang isang susi label=value. At ang value ay ang identifier ng time series kung saan naroroon ang pares label=value.

Kung marami tayong time series na may ibinigay na pares label=value, pagkatapos ay magkakaroon ng maraming mga hilera sa database na ito na may parehong key at magkaiba timeseries_ids. Para makakuha ng listahan ng lahat timeseries_ids, na nagsisimula dito label=prefix, gumagawa kami ng range scan kung saan na-optimize ang database na ito. Iyon ay, pinipili namin ang lahat ng mga linya na nagsisimula sa label=prefix at kunin ang kailangan timeseries_ids.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Narito ang isang sample na pagpapatupad ng kung ano ang magiging hitsura nito sa Go. Mayroon kaming baligtad na index. Ito ang LevelDB.

Ang pag-andar ay kapareho ng para sa walang muwang na pagpapatupad. Inuulit nito ang walang muwang na pagpapatupad halos linya sa linya. Ang tanging punto ay sa halip na lumingon sa map ina-access namin ang inverted index. Nakukuha namin ang lahat ng mga halaga para sa una label=value. Pagkatapos ay dumaan kami sa lahat ng natitirang mga pares label=value at kunin ang kaukulang hanay ng mga metricID para sa kanila. Pagkatapos ay nakita namin ang intersection.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Mukhang maayos ang lahat, ngunit may mga kakulangan sa solusyon na ito. Una nang nagpatupad ang VictoriaMetrics ng inverted index batay sa LevelDB. Pero sa huli, kinailangan kong isuko.

Bakit? Dahil ang LevelDB ay mas mabagal kaysa sa walang muwang na pagpapatupad. Sa isang walang muwang na pagpapatupad, na binigyan ng ibinigay na susi, agad naming kinukuha ang buong slice metricIDs. Ito ay isang napakabilis na operasyon - ang buong slice ay handa nang gamitin.

Sa LevelDB, sa tuwing tatawagin ang isang function GetValues kailangan mong dumaan sa lahat ng mga linya na nagsisimula sa label=value. At kunin ang halaga para sa bawat linya timeseries_ids. Ng mga ganyan timeseries_ids mangolekta ng isang hiwa ng mga ito timeseries_ids. Malinaw, ito ay mas mabagal kaysa sa simpleng pag-access sa isang regular na mapa sa pamamagitan ng key.

Ang pangalawang disbentaha ay ang LevelDB ay nakasulat sa C. Ang pagtawag sa mga function ng C mula sa Go ay hindi masyadong mabilis. Ito ay tumatagal ng daan-daang nanosecond. Ito ay hindi masyadong mabilis, dahil kumpara sa isang regular na function na tawag na nakasulat sa go, na tumatagal ng 1-5 nanosecond, ang pagkakaiba sa pagganap ay sampu-sampung beses. Para sa VictoriaMetrics ito ay isang nakamamatay na kapintasan :)

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Kaya sinulat ko ang sarili kong pagpapatupad ng inverted index. At tinawag niya siya mergeset.

Ang Mergeset ay batay sa istraktura ng data ng MergeTree. Ang istruktura ng data na ito ay hiniram mula sa ClickHouse. Malinaw, ang mergeset ay dapat na ma-optimize para sa mabilis na paghahanap timeseries_ids ayon sa ibinigay na susi. Ang Mergeset ay ganap na nakasulat sa Go. Nakikita mo Mga mapagkukunan ng VictoriaMetrics sa GitHub. Ang pagpapatupad ng mergeset ay nasa folder /lib/mergeset. Maaari mong subukang alamin kung ano ang nangyayari doon.

Ang mergeset API ay halos kapareho sa LevelDB at RocksDB. Iyon ay, pinapayagan ka nitong mabilis na mag-save ng mga bagong tala doon at mabilis na pumili ng mga tala sa pamamagitan ng isang ibinigay na prefix.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Pag-uusapan natin ang mga disadvantages ng mergeset mamaya. Ngayon pag-usapan natin kung anong mga problema ang lumitaw sa VictoriaMetrics sa produksyon kapag nagpapatupad ng inverted index.

Bakit sila bumangon?

Ang unang dahilan ay ang mataas na churn rate. Isinalin sa Russian, ito ay isang madalas na pagbabago sa serye ng oras. Ito ay kapag nagtatapos ang isang serye ng oras at nagsimula ang isang bagong serye, o maraming bagong serye ng panahon ang nagsisimula. At madalas itong nangyayari.

Ang pangalawang dahilan ay ang malaking bilang ng mga serye ng oras. Sa simula, kapag ang pagsubaybay ay nakakakuha ng katanyagan, ang bilang ng mga serye ng oras ay maliit. Halimbawa, para sa bawat computer kailangan mong subaybayan ang CPU, memorya, network at disk load. 4 na time series bawat computer. Sabihin nating mayroon kang 100 computer at 400 time series. Ito ay napakaliit.

Sa paglipas ng panahon, nalaman ng mga tao na maaari nilang sukatin ang mas detalyadong impormasyon. Halimbawa, sukatin ang pag-load hindi ng buong processor, ngunit hiwalay sa bawat core ng processor. Kung mayroon kang 40 core ng processor, mayroon kang 40 beses na mas maraming time series para sukatin ang pagkarga ng processor.

Ngunit hindi lang iyon. Ang bawat core ng processor ay maaaring magkaroon ng ilang mga estado, tulad ng idle, kapag ito ay idle. At gumana din sa espasyo ng gumagamit, magtrabaho sa espasyo ng kernel at iba pang mga estado. At ang bawat ganoong estado ay maaari ding masukat bilang isang hiwalay na serye ng oras. Dagdag dito, pinapataas nito ang bilang ng mga hilera ng 7-8 beses.

Mula sa isang sukatan nakakuha kami ng 40 x 8 = 320 na sukatan para sa isang computer lang. I-multiply sa 100, makakakuha tayo ng 32 sa halip na 000.

Pagkatapos ay dumating si Kubernetes. At lumala ito dahil maaaring mag-host ang Kubernetes ng maraming iba't ibang serbisyo. Ang bawat serbisyo sa Kubernetes ay binubuo ng maraming pod. At lahat ng ito ay kailangang subaybayan. Bilang karagdagan, mayroon kaming patuloy na pag-deploy ng mga bagong bersyon ng iyong mga serbisyo. Para sa bawat bagong bersyon, dapat gumawa ng bagong time series. Bilang resulta, ang bilang ng mga serye ng oras ay lumalaki nang husto at nahaharap tayo sa problema ng isang malaking bilang ng mga serye ng oras, na tinatawag na high-cardinality. Matagumpay itong nakayanan ng VictoriaMetrics kumpara sa iba pang mga database ng serye ng oras.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Tingnan natin ang mataas na rate ng churn. Ano ang sanhi ng mataas na churn rate sa produksyon? Dahil ang ilang mga kahulugan ng mga label at tag ay patuloy na nagbabago.

Halimbawa, kunin ang Kubernetes, na may konsepto deployment, ibig sabihin, kapag ang isang bagong bersyon ng iyong application ay inilunsad. Para sa ilang kadahilanan, nagpasya ang mga developer ng Kubernetes na idagdag ang deployment id sa label.

Ano ang humantong sa? Bukod dito, sa bawat bagong deployment, naaantala ang lahat ng lumang serye ng panahon, at sa halip na mga ito, nagsisimula ang bagong serye ng panahon sa bagong halaga ng label deployment_id. Maaaring magkaroon ng daan-daang libo at kahit milyon-milyong mga naturang row.

Ang mahalagang bagay sa lahat ng ito ay ang kabuuang bilang ng mga serye ng oras ay lumalaki, ngunit ang bilang ng mga serye ng oras na kasalukuyang aktibo at tumatanggap ng data ay nananatiling pare-pareho. Ang estado na ito ay tinatawag na mataas na churn rate.

Ang pangunahing problema ng mataas na rate ng churn ay upang matiyak ang patuloy na bilis ng paghahanap para sa lahat ng serye ng oras para sa isang naibigay na hanay ng mga label sa isang tiyak na agwat ng oras. Kadalasan ito ang agwat ng oras para sa huling oras o huling araw.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Paano malutas ang problemang ito? Narito ang unang opsyon. Ito ay upang hatiin ang baligtad na index sa mga independiyenteng bahagi sa paglipas ng panahon. Iyon ay, lumipas ang ilang agwat ng oras, natapos namin ang pagtatrabaho sa kasalukuyang inverted index. At lumikha ng bagong inverted index. Lumipas ang isa pang agwat ng oras, lumikha kami ng isa at isa pa.

At kapag nagsa-sample mula sa mga baligtad na indeks na ito, makikita natin ang isang hanay ng mga baligtad na indeks na nasa loob ng ibinigay na pagitan. At, ayon dito, pipiliin namin ang id ng serye ng oras mula doon.

Makakatipid ito ng mga mapagkukunan dahil hindi natin kailangang tingnan ang mga bahagi na hindi nasa loob ng ibinigay na agwat. Iyon ay, kadalasan, kung pipili kami ng data para sa huling oras, pagkatapos ay para sa mga nakaraang agwat ng oras ay nilalaktawan namin ang mga query.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

May isa pang pagpipilian upang malutas ang problemang ito. Ito ay upang mag-imbak para sa bawat araw ng isang hiwalay na listahan ng mga id ng serye ng oras na naganap sa araw na iyon.

Ang bentahe ng solusyong ito kumpara sa nakaraang solusyon ay ang hindi namin duplicate na impormasyon ng serye ng oras na hindi nawawala sa paglipas ng panahon. Ang mga ito ay patuloy na naroroon at hindi nagbabago.

Ang kawalan ay ang ganitong solusyon ay mas mahirap ipatupad at mas mahirap i-debug. At pinili ng VictoriaMetrics ang solusyon na ito. Ganito ang nangyari sa kasaysayan. Ang solusyon na ito ay gumaganap din nang maayos kumpara sa nauna. Dahil ang solusyon na ito ay hindi ipinatupad dahil sa ang katunayan na ito ay kinakailangan upang duplicate ang data sa bawat partition para sa mga serye ng oras na hindi nagbabago, ibig sabihin, na hindi nawawala sa paglipas ng panahon. Pangunahing na-optimize ang VictoriaMetrics para sa pagkonsumo ng espasyo sa disk, at ang nakaraang pagpapatupad ay nagpalala ng pagkonsumo ng espasyo sa disk. Ngunit ang pagpapatupad na ito ay mas angkop para sa pagliit ng pagkonsumo ng espasyo sa disk, kaya ito ang napili.

Kinailangan kong ipaglaban siya. Ang pakikibaka ay na sa pagpapatupad na ito kailangan mo pa ring pumili ng isang mas malaking numero timeseries_ids para sa data kaysa kapag ang inverted index ay time partitioned.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Paano natin nalutas ang problemang ito? Nalutas namin ito sa orihinal na paraan - sa pamamagitan ng pag-iimbak ng ilang time series identifier sa bawat inverted index entry sa halip na isang identifier. Ibig sabihin, may susi tayo label=value, na nangyayari sa bawat serye ng oras. At ngayon nagtitipid kami ng ilan timeseries_ids sa isang entry.

Narito ang isang halimbawa. Dati mayroon kaming N entry, ngunit ngayon mayroon kaming isang entry na ang prefix ay pareho sa lahat ng iba pa. Para sa nakaraang entry, naglalaman ang value ng lahat ng time series id.

Ginawa nitong posible na taasan ang bilis ng pag-scan ng naturang inverted index hanggang 10 beses. At pinahintulutan kaming bawasan ang pagkonsumo ng memorya para sa cache, dahil ngayon ay iniimbak namin ang string label=value isang beses lang sa cache na magkasama N beses. At maaaring malaki ang linyang ito kung mag-iimbak ka ng mahahabang linya sa iyong mga tag at label, na gustong-gusto ng Kubernetes na itulak doon.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ang isa pang opsyon para sa pagpapabilis ng paghahanap sa isang baligtad na index ay sharding. Paglikha ng ilang inverted index sa halip na isa at sharding data sa pagitan ng mga ito sa pamamagitan ng key. Ito ay isang set key=value singaw. Iyon ay, nakakakuha kami ng ilang mga independiyenteng inverted index, na maaari naming i-query nang magkatulad sa ilang mga processor. Pinapayagan lang ng mga nakaraang pagpapatupad ang operasyon sa single-processor mode, ibig sabihin, pag-scan ng data sa isang core lang. Binibigyang-daan ka ng solusyong ito na mag-scan ng data sa ilang mga core nang sabay-sabay, gaya ng gustong gawin ng ClickHouse. Ito ang plano naming ipatupad.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ngayon bumalik tayo sa ating mga tupa - sa intersection function timeseries_ids. Isaalang-alang natin kung anong mga pagpapatupad ang maaaring mayroon. Ang function na ito ay nagbibigay-daan sa iyo upang mahanap timeseries_ids para sa isang naibigay na set label=value.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ang unang pagpipilian ay isang walang muwang na pagpapatupad. Dalawang nested na mga loop. Dito nakuha namin ang input ng function intersectInts dalawang hiwa - a ΠΈ b. Sa output, dapat itong ibalik sa amin ang intersection ng mga hiwa na ito.

Mukhang ganito ang isang walang muwang na pagpapatupad. Inuulit namin ang lahat ng mga halaga mula sa slice a, sa loob ng loop na ito ay dumaan tayo sa lahat ng mga halaga ng slice b. At pinagkukumpara natin sila. Kung magkatugma sila, may nakita kaming intersection. At i-save ito result.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ano ang mga disadvantages? Quadratic complexity ang pangunahing disbentaha nito. Halimbawa, kung ang iyong mga sukat ay slice a ΠΈ b isang milyon sa isang pagkakataon, kung gayon ang function na ito ay hindi kailanman magbabalik ng sagot sa iyo. Dahil kakailanganin nitong gumawa ng isang trilyong pag-ulit, na marami kahit para sa mga modernong computer.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ang pangalawang pagpapatupad ay batay sa mapa. Gumagawa kami ng mapa. Inilalagay namin ang lahat ng mga halaga mula sa slice sa mapa na ito a. Pagkatapos ay dumaan kami sa hiwa sa isang hiwalay na loop b. At sinusuri namin kung ang halagang ito ay mula sa slice b sa mapa. Kung mayroon ito, pagkatapos ay idagdag ito sa resulta.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ano ang mga benepisyo? Ang kalamangan ay mayroon lamang linear complexity. Iyon ay, ang function ay execute nang mas mabilis para sa mas malalaking hiwa. Para sa isang milyong-size na slice, ang function na ito ay isasagawa sa 2 milyong mga pag-ulit, kumpara sa trilyong pag-ulit ng nakaraang function.

Ang downside ay ang function na ito ay nangangailangan ng mas maraming memorya upang likhain ang mapa na ito.

Ang pangalawang disbentaha ay ang malaking overhead para sa pag-hash. Ang disbentaha na ito ay hindi masyadong halata. At para sa amin ay hindi rin masyadong halata, kaya noong una sa VictoriaMetrics ang pagpapatupad ng intersection ay sa pamamagitan ng mapa. Ngunit pagkatapos ay ipinakita ng pag-profile na ang pangunahing oras ng processor ay ginugugol sa pagsulat sa mapa at pagsuri para sa pagkakaroon ng isang halaga sa mapa na ito.

Bakit nasasayang ang oras ng CPU sa mga lugar na ito? Dahil nagsasagawa ng hashing operation si Go sa mga linyang ito. Iyon ay, kinakalkula nito ang hash ng susi upang pagkatapos ay ma-access ito sa isang naibigay na index sa HashMap. Ang operasyon ng pagkalkula ng hash ay nakumpleto sa sampu-sampung nanosecond. Mabagal ito para sa VictoriaMetrics.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Nagpasya akong magpatupad ng bitset na partikular na na-optimize para sa kasong ito. Ito ang hitsura ngayon ng intersection ng dalawang hiwa. Dito kami lumikha ng isang bitset. Nagdaragdag kami ng mga elemento mula sa unang slice dito. Pagkatapos ay suriin namin ang pagkakaroon ng mga elementong ito sa pangalawang hiwa. At idagdag ang mga ito sa resulta. Ibig sabihin, halos walang pinagkaiba sa naunang halimbawa. Ang tanging bagay dito ay pinalitan namin ang access sa mapa ng mga custom na function add ΠΈ has.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Sa unang sulyap, tila dapat itong gumana nang mas mabagal, kung dati ay isang karaniwang mapa ang ginamit doon, at pagkatapos ay tinawag ang ilang iba pang mga pag-andar, ngunit ipinapakita ng profiling na ang bagay na ito ay gumagana ng 10 beses na mas mabilis kaysa sa karaniwang mapa sa kaso ng VictoriaMetrics.

Bilang karagdagan, gumagamit ito ng mas kaunting memorya kumpara sa pagpapatupad ng mapa. Dahil nag-iimbak kami ng mga bit dito sa halip na walong-byte na mga halaga.

Ang kawalan ng pagpapatupad na ito ay hindi ito masyadong halata, hindi mahalaga.

Ang isa pang disbentaha na maaaring hindi mapansin ng marami ay ang pagpapatupad na ito ay maaaring hindi gumana nang maayos sa ilang mga kaso. Ibig sabihin, ito ay na-optimize para sa isang partikular na kaso, para sa kasong ito ng intersection ng VictoriaMetrics time series id. Hindi ito nangangahulugan na ito ay angkop para sa lahat ng mga kaso. Kung ito ay ginamit nang hindi tama, hindi kami makakakuha ng isang pagtaas ng pagganap, ngunit isang out of memory error at isang pagbagal sa pagganap.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Isaalang-alang natin ang pagpapatupad ng istrukturang ito. Kung gusto mong tingnan, ito ay matatagpuan sa mga pinagmumulan ng VictoriaMetrics, sa folder lib/uint64set. Ito ay partikular na na-optimize para sa VictoriaMetrics case, kung saan timeseries_id ay isang 64-bit na halaga, kung saan ang unang 32 bit ay karaniwang pare-pareho at ang huling 32 bits lamang ang nagbabago.

Ang istraktura ng data na ito ay hindi naka-imbak sa disk, ito ay nagpapatakbo lamang sa memorya.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Narito ang API nito. Ito ay hindi masyadong kumplikado. Ang API ay partikular na iniayon sa isang partikular na halimbawa ng paggamit ng VictoriaMetrics. Iyon ay, walang mga hindi kinakailangang pag-andar dito. Narito ang mga function na tahasang ginagamit ng VictoriaMetrics.

May mga function add, na nagdaragdag ng mga bagong halaga. May function has, na sumusuri para sa mga bagong halaga. At mayroong isang function del, na nag-aalis ng mga halaga. Mayroong function ng katulong len, na nagbabalik ng laki ng set. Function clone maraming clone. At pag-andar appendto kino-convert ang set na ito sa slice timeseries_ids.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ganito ang hitsura ng pagpapatupad ng istruktura ng data na ito. Ang set ay may dalawang elemento:

  • ItemsCount ay isang helper field upang mabilis na maibalik ang bilang ng mga elemento sa isang set. Posible itong gawin nang wala itong pantulong na field, ngunit kailangan itong idagdag dito dahil madalas na tinatanong ng VictoriaMetrics ang haba ng bitset sa mga algorithm nito.

  • Ang pangalawang larangan ay buckets. Ito ay hiwa mula sa istraktura bucket32. Ang bawat istraktura ay nag-iimbak hi patlang. Ito ang itaas na 32 bits. At dalawang hiwa - b16his ΠΈ buckets ng bucket16 mga istruktura.

Ang nangungunang 16 bits ng ikalawang bahagi ng 64-bit na istraktura ay naka-imbak dito. At dito naka-imbak ang mga bitset para sa mas mababang 16 bits ng bawat byte.

Bucket64 binubuo ng isang array uint64. Ang haba ay kinakalkula gamit ang mga constant na ito. Sa isa bucket16 maximum na maaaring maimbak 2^16=65536 bit. Kung hahatiin mo ito sa 8, ito ay 8 kilobytes. Kung hahatiin mo ulit sa 8, ito ay 1000 uint64 ibig sabihin. Yan ay Bucket16 – ito ang aming 8-kilobyte na istraktura.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Tingnan natin kung paano ipinatupad ang isa sa mga pamamaraan ng istrukturang ito para sa pagdaragdag ng bagong halaga.

Nagsisimula ang lahat sa uint64 mga kahulugan. Kinakalkula namin ang itaas na 32 bits, kinakalkula namin ang mas mababang 32 bits. Pagdaanan natin ang lahat buckets. Inihahambing namin ang nangungunang 32 bits sa bawat bucket sa halagang idinaragdag. At kung magkatugma sila, pagkatapos ay tinatawag namin ang function add sa istruktura b32 buckets. At idagdag ang mas mababang 32 bits doon. At kung bumalik ito true, nangangahulugan ito na nagdagdag kami ng ganoong halaga doon at wala kaming ganoong halaga. Kung babalik ito false, pagkatapos ay umiral na ang gayong kahulugan. Pagkatapos ay pinapataas namin ang bilang ng mga elemento sa istraktura.

Kung hindi pa namin nahanap ang kailangan mo bucket gamit ang kinakailangang hi-value, pagkatapos ay tinatawag namin ang function addAlloc, na gagawa ng bago bucket, idinaragdag ito sa istraktura ng bucket.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Ito ang pagpapatupad ng function b32.add. Ito ay katulad ng nakaraang pagpapatupad. Kinakalkula namin ang pinakamahalagang 16 bits, ang hindi bababa sa makabuluhang 16 bits.

Pagkatapos ay dumaan kami sa lahat ng itaas na 16 bits. Nakahanap kami ng mga tugma. At kung may tugma, tinatawag namin ang paraan ng pagdaragdag, na isasaalang-alang namin sa susunod na pahina para sa bucket16.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

At narito ang pinakamababang antas, na dapat i-optimize hangga't maaari. Kinakalkula namin para sa uint64 halaga ng id sa slice bit at gayundin bitmask. Isa itong mask para sa isang ibinigay na 64-bit na halaga, na maaaring gamitin upang suriin ang presensya ng bit na ito, o itakda ito. Sinusuri namin upang makita kung ang bit na ito ay nakatakda at nakatakda ito, at bumalik sa presensya. Ito ang aming pagpapatupad, na nagbigay-daan sa aming mapabilis ang operasyon ng mga intersecting id ng time series ng 10 beses kumpara sa mga conventional na mapa.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

Bilang karagdagan sa pag-optimize na ito, ang VictoriaMetrics ay may maraming iba pang mga pag-optimize. Karamihan sa mga pag-optimize na ito ay idinagdag para sa isang kadahilanan, ngunit pagkatapos i-profile ang code sa produksyon.

Ito ang pangunahing tuntunin ng pag-optimize - huwag magdagdag ng pag-optimize sa pag-aakalang magkakaroon ng bottleneck dito, dahil maaaring lumabas na hindi magkakaroon ng bottleneck doon. Karaniwang pinapababa ng pag-optimize ang kalidad ng code. Samakatuwid, ito ay nagkakahalaga ng pag-optimize lamang pagkatapos ng pag-profile at mas mabuti sa produksyon, upang ito ay tunay na data. Kung may interesado, maaari mong tingnan ang source code ng VictoriaMetrics at tuklasin ang iba pang mga optimization na naroroon.

Pumunta sa mga pag-optimize sa VictoriaMetrics. Alexander Valyalkin

May tanong ako tungkol sa bitset. Katulad na katulad sa pagpapatupad ng C++ vector bool, na-optimize na bitset. Kinuha mo ba ang pagpapatupad mula doon?

Hindi, hindi mula doon. Kapag ipinatupad ang bitset na ito, ginabayan ako ng kaalaman sa istruktura ng mga timeseries ng mga id na ito, na ginagamit sa VictoriaMetrics. At ang kanilang istraktura ay tulad na ang itaas na 32 bit ay karaniwang pare-pareho. Ang mas mababang 32 bits ay maaaring magbago. Kung mas mababa ang bit, mas madalas itong magbago. Samakatuwid, ang pagpapatupad na ito ay partikular na na-optimize para sa istruktura ng data na ito. Ang pagpapatupad ng C++, sa pagkakaalam ko, ay na-optimize para sa pangkalahatang kaso. Kung nag-optimize ka para sa pangkalahatang kaso, nangangahulugan ito na hindi ito ang pinakamainam para sa isang partikular na kaso.

Pinapayuhan din kita na panoorin ang ulat ni Alexey Milovid. Mga isang buwan na ang nakalipas, nagsalita siya tungkol sa pag-optimize sa ClickHouse para sa mga partikular na espesyalisasyon. Sinasabi lang niya na sa pangkalahatang kaso, ang isang C++ na pagpapatupad o ilang iba pang pagpapatupad ay iniayon upang gumana nang maayos sa karaniwan sa isang ospital. Maaari itong gumanap nang mas malala kaysa sa isang pagpapatupad na partikular sa kaalaman tulad ng sa amin, kung saan alam namin na ang nangungunang 32 bit ay halos pare-pareho.

May pangalawang tanong ako. Ano ang pangunahing pagkakaiba mula sa InfluxDB?

Mayroong maraming mga pangunahing pagkakaiba. Sa mga tuntunin ng pagganap at pagkonsumo ng memorya, ang InfluxDB sa mga pagsubok ay nagpapakita ng 10 beses na mas maraming pagkonsumo ng memorya para sa mataas na cardinality na serye ng oras, kapag mayroon kang marami sa kanila, halimbawa, milyon-milyon. Halimbawa, ang VictoriaMetrics ay gumagamit ng 1 GB bawat milyong aktibong row, habang ang InfluxDB ay gumagamit ng 10 GB. At iyon ay isang malaking pagkakaiba.

Ang pangalawang pangunahing pagkakaiba ay ang InfluxDB ay may kakaibang mga wika ng query - Flux at InfluxQL. Ang mga ito ay hindi masyadong maginhawa para sa pagtatrabaho sa mga serye ng oras kumpara sa PromQL, na sinusuportahan ng VictoriaMetrics. Ang PromQL ay isang query language mula sa Prometheus.

At ang isa pang pagkakaiba ay ang InfluxDB ay may bahagyang kakaibang modelo ng data, kung saan ang bawat linya ay maaaring mag-imbak ng ilang mga patlang na may ibang hanay ng mga tag. Ang mga linyang ito ay higit na nahahati sa iba't ibang mga talahanayan. Ang mga karagdagang komplikasyon na ito ay nagpapalubha sa kasunod na trabaho sa database na ito. Mahirap suportahan at intindihin.

Sa VictoriaMetrics lahat ay mas simple. Doon, ang bawat serye ng oras ay isang mahalagang halaga. Ang halaga ay isang hanay ng mga puntos - (timestamp, value), at ang susi ay ang set label=value. Walang paghihiwalay sa pagitan ng mga patlang at mga sukat. Pinapayagan ka nitong pumili ng anumang data at pagkatapos ay pagsamahin, idagdag, ibawas, i-multiply, hatiin, hindi tulad ng InfluxDB kung saan ang mga kalkulasyon sa pagitan ng iba't ibang mga hilera ay hindi pa rin ipinapatupad sa pagkakaalam ko. Kahit na sila ay ipinatupad, ito ay mahirap, kailangan mong magsulat ng maraming code.

May clarifying question ako. Naintindihan ko ba nang tama na mayroong ilang uri ng problema na iyong napag-usapan, na ang baligtad na index na ito ay hindi magkasya sa memorya, kaya mayroong partitioning doon?

Una, nagpakita ako ng walang muwang na pagpapatupad ng isang baligtad na index sa isang karaniwang Go map. Ang pagpapatupad na ito ay hindi angkop para sa mga database dahil ang baligtad na index na ito ay hindi nai-save sa disk, at ang database ay dapat na i-save sa disk upang ang data na ito ay mananatiling available sa pag-restart. Sa pagpapatupad na ito, kapag na-restart mo ang application, mawawala ang iyong inverted index. At mawawalan ka ng access sa lahat ng data dahil hindi mo ito mahahanap.

Kamusta! Salamat sa ulat! Ang pangalan ko ay Pavel. Ako ay mula sa Wildberries. Mayroon akong ilang mga katanungan para sa iyo. Tanong isa. Sa palagay mo ba kung pumili ka ng ibang prinsipyo sa pagbuo ng arkitektura ng iyong aplikasyon at paghahati ng data sa paglipas ng panahon, marahil ay nagawa mong i-intersect ang data kapag naghahanap, batay lamang sa katotohanan na ang isang partisyon ay naglalaman ng data para sa isa tagal ng panahon , iyon ay, sa isang agwat ng oras at hindi mo na kailangang mag-alala tungkol sa katotohanan na ang iyong mga piraso ay nakakalat sa ibang paraan? Tanong numero 2 - dahil nagpapatupad ka ng isang katulad na algorithm na may bitset at lahat ng iba pa, pagkatapos ay marahil sinubukan mong gumamit ng mga tagubilin sa processor? Siguro nasubukan mo na ang mga ganitong pag-optimize?

Sasagutin ko kaagad ang pangalawa. Hindi pa tayo umabot sa ganun. Ngunit kung kinakailangan, pupunta tayo doon. At ang una, ano ang tanong?

Tinalakay mo ang dalawang senaryo. At sinabi nila na pinili nila ang pangalawa na may mas kumplikadong pagpapatupad. At hindi nila ginusto ang una, kung saan ang data ay nahahati sa oras.

Oo. Sa unang kaso, ang kabuuang dami ng index ay magiging mas malaki, dahil sa bawat partition kailangan naming mag-imbak ng mga duplicate na data para sa mga serye ng oras na magpapatuloy sa lahat ng mga partisyon na ito. At kung ang iyong time series churn rate ay maliit, ibig sabihin, ang parehong serye ay patuloy na ginagamit, kung gayon sa unang kaso mas malaki ang mawawala sa atin sa dami ng disk space na inookupahan kumpara sa pangalawang kaso.

At kaya - oo, ang paghahati ng oras ay isang magandang opsyon. Ginagamit ito ng Prometheus. Ngunit ang Prometheus ay may isa pang sagabal. Kapag pinagsasama ang mga piraso ng data na ito, kailangan nitong panatilihin sa memorya ng meta impormasyon para sa lahat ng mga label at timeseries. Samakatuwid, kung ang mga piraso ng data na pinagsasama nito ay malaki, kung gayon ang pagkonsumo ng memorya ay tumataas nang husto sa panahon ng pagsasama, hindi tulad ng VictoriaMetrics. Kapag pinagsasama, ang VictoriaMetrics ay hindi kumukonsumo ng memorya; ilang kilobytes lamang ang natupok, anuman ang laki ng pinagsama-samang mga piraso ng data.

Ang algorithm na iyong ginagamit ay gumagamit ng memorya. Minamarkahan nito ang mga tag ng timeseries na naglalaman ng mga halaga. At sa ganitong paraan masusuri mo ang nakapares na presensya sa isang array ng data at sa isa pa. At naiintindihan mo kung naganap ang intersect o hindi. Karaniwan, ang mga database ay nagpapatupad ng mga cursor at iterator na nag-iimbak ng kanilang kasalukuyang nilalaman at tumatakbo sa pinagsunod-sunod na data dahil sa simpleng pagiging kumplikado ng mga operasyong ito.

Bakit hindi kami gumamit ng mga cursor para mag-traverse ng data?

Oo.

Nag-iimbak kami ng mga pinagsunod-sunod na row sa LevelDB o mergeset. Maaari naming ilipat ang cursor at hanapin ang intersection. Bakit hindi natin ito gamitin? Ang bagal kasi. Dahil ang mga cursor ay nangangahulugan na kailangan mong tumawag ng isang function para sa bawat linya. Ang isang function na tawag ay 5 nanoseconds. At kung mayroon kang 100 na linya, lumalabas na gumugugol kami ng kalahating segundo sa pagtawag lamang sa function.

May ganyan, oo. At ang huling tanong ko. Maaaring medyo kakaiba ang tanong. Bakit hindi posible na basahin ang lahat ng kinakailangang pinagsama-sama sa sandaling dumating ang data at i-save ang mga ito sa kinakailangang form? Bakit mag-imbak ng malalaking volume sa ilang system tulad ng VictoriaMetrics, ClickHouse, atbp., at pagkatapos ay gumugol ng maraming oras sa mga ito?

Magbibigay ako ng halimbawa para mas malinaw. Sabihin natin kung paano gumagana ang isang maliit na laruang speedometer? Itinatala nito ang distansya na iyong nilakbay, sa lahat ng oras na idinaragdag ito sa isang halaga, at ang pangalawang beses. At naghahati. At nakakakuha ng average na bilis. Maaari mong gawin ang tungkol sa parehong bagay. Magdagdag ng lahat ng kinakailangang mga katotohanan sa mabilisang.

Okay, naiintindihan ko ang tanong. May lugar ang iyong halimbawa. Kung alam mo kung anong mga pinagsama-samang kailangan mo, ito ang pinakamahusay na pagpapatupad. Ngunit ang problema ay na-save ng mga tao ang mga sukatan na ito, ilang data sa ClickHouse at hindi pa nila alam kung paano nila pagsasama-samahin at i-filter ang mga ito sa hinaharap, kaya kailangan nilang i-save ang lahat ng raw data. Ngunit kung alam mong kailangan mong kalkulahin ang isang bagay sa karaniwan, kung gayon bakit hindi kalkulahin ito sa halip na mag-imbak ng isang grupo ng mga hilaw na halaga doon? Ngunit ito ay kung alam mo kung ano mismo ang kailangan mo.

Sa pamamagitan ng paraan, ang mga database para sa pag-iimbak ng mga serye ng oras ay sumusuporta sa pagbibilang ng mga pinagsama-samang. Halimbawa, sinusuportahan ng Prometheus mga tuntunin sa pag-record. Ibig sabihin, magagawa ito kung alam mo kung anong mga unit ang kakailanganin mo. Ang VictoriaMetrics ay wala pa nito, ngunit karaniwan itong nauuna sa Prometheus, kung saan ito ay maaaring gawin sa mga panuntunan sa pag-recoding.

Halimbawa, sa dati kong trabaho kailangan kong bilangin ang bilang ng mga kaganapan sa isang sliding window sa nakalipas na oras. Ang problema ay kailangan kong gumawa ng custom na pagpapatupad sa Go, ibig sabihin, isang serbisyo para sa pagbibilang ng bagay na ito. Ang serbisyong ito sa huli ay hindi mahalaga, dahil mahirap kalkulahin. Ang pagpapatupad ay maaaring maging simple kung kailangan mong bilangin ang ilang mga pinagsama-sama sa mga nakapirming agwat ng oras. Kung gusto mong bilangin ang mga kaganapan sa isang sliding window, hindi ito kasing simple ng tila. Sa palagay ko ay hindi pa ito naipapatupad sa ClickHouse o sa mga database ng timeseries, dahil mahirap itong ipatupad.

At isa pang tanong. Pinag-uusapan lang namin ang tungkol sa pag-average, at naalala ko na may isang bagay na gaya ng Graphite na may Carbon backend. At alam niya kung paano manipis ang lumang data, iyon ay, mag-iwan ng isang punto bawat minuto, isang punto bawat oras, atbp. Sa prinsipyo, ito ay medyo maginhawa kung kailangan namin ng hilaw na data, medyo nagsasalita, para sa isang buwan, at lahat ng iba pa ay maaaring mapayat. Ngunit hindi sinusuportahan ng Prometheus at VictoriaMetrics ang pagpapaandar na ito. May balak ba itong suportahan? Kung hindi, bakit hindi?

Salamat sa tanong. Pana-panahong tinatanong ng aming mga user ang tanong na ito. Nagtatanong sila kung kailan kami magdadagdag ng suporta para sa downsampling. Mayroong ilang mga problema dito. Una, naiintindihan ng bawat gumagamit downsampling ibang bagay: may gustong makakuha ng anumang di-makatwirang punto sa isang naibigay na agwat, may gusto ng maximum, minimum, average na mga halaga. Kung maraming mga system ang nagsusulat ng data sa iyong database, hindi mo ito maaaring pagsama-samahin. Maaaring ang bawat sistema ay nangangailangan ng iba't ibang pagnipis. At ito ay mahirap ipatupad.

At ang pangalawang bagay ay ang VictoriaMetrics, tulad ng ClickHouse, ay na-optimize para sa pagtatrabaho sa malalaking halaga ng hilaw na data, kaya maaari itong pala ng isang bilyong linya sa mas mababa sa isang segundo kung mayroon kang maraming mga core sa iyong system. Pag-scan ng mga punto ng serye ng oras sa VictoriaMetrics – 50 puntos bawat segundo bawat core. At ang pagganap na ito ay nasusukat sa mga kasalukuyang core. Iyon ay, kung mayroon kang 000 core, halimbawa, mag-i-scan ka ng isang bilyong puntos bawat segundo. At ang pag-aari na ito ng VictoriaMetrics at ClickHouse ay binabawasan ang pangangailangan para sa downsamling.

Ang isa pang tampok ay ang epektibong pag-compress ng VictoriaMetrics sa data na ito. Ang compression sa average sa produksyon ay mula 0,4 hanggang 0,8 bytes bawat punto. Ang bawat punto ay isang timestamp + value. At ito ay naka-compress sa mas mababa sa isang byte sa karaniwan.

Sergey. May tanong ako. Ano ang pinakamababang oras ng pag-record na quantum?

Isang millisecond. Nakipag-usap kami kamakailan sa iba pang mga developer ng database ng time series. Ang kanilang minimum na time slice ay isang segundo. At sa Graphite, halimbawa, ito rin ay isang segundo. Sa OpenTSDB isa rin itong segundo. Ang InfluxDB ay may katumpakan ng nanosecond. Sa VictoriaMetrics ito ay isang millisecond, dahil sa Prometheus ito ay isang millisecond. At ang VictoriaMetrics ay orihinal na binuo bilang malayong imbakan para sa Prometheus. Ngunit ngayon ay makakapag-save ito ng data mula sa ibang mga system.

Sinabi ng taong nakausap ko na mayroon silang pangalawa-sa-segundong katumpakan - sapat na iyon para sa kanila dahil ito ay depende sa uri ng data na iniimbak sa database ng serye ng oras. Kung ito ay data ng DevOps o data mula sa imprastraktura, kung saan kinokolekta mo ito sa pagitan ng 30 segundo, bawat minuto, kung gayon ang pangalawang katumpakan ay sapat na, hindi mo na kailangan ng mas kaunti. At kung kinokolekta mo ang data na ito mula sa mga high frequency trading system, kailangan mo ng nanosecond accuracy.

Ang katumpakan ng Millisecond sa VictoriaMetrics ay angkop din para sa kaso ng DevOps, at maaaring maging angkop para sa karamihan ng mga kaso na binanggit ko sa simula ng ulat. Ang tanging bagay na maaaring hindi ito angkop ay ang mga high frequency trading system.

Salamat! At isa pang tanong. Ano ang compatibility sa PromQL?

Buong backwards compatibility. Ganap na sinusuportahan ng VictoriaMetrics ang PromQL. Bilang karagdagan, nagdaragdag ito ng karagdagang advanced na pag-andar sa PromQL, na tinatawag na SukatanQL. May isang pag-uusap sa YouTube tungkol sa pinahabang pagpapagana na ito. Nagsalita ako sa Monitoring Meetup noong tagsibol sa St. Petersburg.

Channel ng Telegram VictoriaMetrics.

Ang mga rehistradong user lamang ang maaaring lumahok sa survey. Mag-sign in, pakiusap

Ano ang pumipigil sa iyo na lumipat sa VictoriaMetrics bilang iyong pangmatagalang storage para sa Prometheus? (Isulat sa mga komento, idaragdag ko ito sa poll))

  • 71,4%Hindi ako gumagamit ng Prometheus5

  • 28,6%Hindi alam ang tungkol sa VictoriaMetrics2

7 user ang bumoto. 12 na user ang umiwas.

Pinagmulan: www.habr.com

Magdagdag ng komento