Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Առաջարկում եմ կարդալ Ալեքսանդր Վալյալկինի 2019-ի վերջին զեկույցի սղագրությունը «Գնա օպտիմալացումներ VictoriaMetrics-ում»

VictoriaMetrics — արագ և մասշտաբային DBMS՝ տվյալների պահպանման և մշակման համար ժամանակային շարքի տեսքով (գրառումը ձևավորում է ժամանակը և այս ժամանակին համապատասխան արժեքների մի շարք, օրինակ՝ ստացված սենսորների կարգավիճակի պարբերական հարցումների կամ հավաքագրման միջոցով։ չափումներ):

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ահա այս զեկույցի տեսանյութի հղումը. https://youtu.be/MZ5P21j_HLE

Սլայդներ

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Պատմեք մեզ Ձեր մասին. Ես Ալեքսանդր Վալյալկինն եմ։ Այստեղ իմ GitHub հաշիվը. Ես կրքոտ եմ Go-ի և կատարողականի օպտիմալացման հարցում: Ես գրել եմ շատ օգտակար և ոչ այնքան օգտակար գրադարաններ։ Նրանք սկսում են կամից fast, կամ հետ quick նախածանց.

Ես այժմ աշխատում եմ VictoriaMetrics-ի վրա: Ի՞նչ է դա և ինչ եմ ես անում այնտեղ: Այս մասին ես կխոսեմ այս շնորհանդեսում:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Զեկույցի ուրվագիծը հետևյալն է.

  • Նախ, ես ձեզ կասեմ, թե ինչ է VictoriaMetrics-ը:
  • Այնուհետև ես ձեզ կասեմ, թե որոնք են ժամանակային շարքերը:
  • Հետո ես ձեզ կասեմ, թե ինչպես է աշխատում ժամանակային շարքերի տվյալների բազան:
  • Հաջորդը, ես ձեզ կասեմ տվյալների բազայի ճարտարապետության մասին. ինչից է այն բաղկացած:
  • Եվ հետո եկեք անցնենք VictoriaMetrics-ի օպտիմալացումներին: Սա շրջված ինդեքսի օպտիմալացում է և Go-ում բիթերի ներդրման օպտիմալացում:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Հանդիսատեսից որևէ մեկը գիտի՞, թե ինչ է VictoriaMetrics-ը: Վայ, շատերն արդեն գիտեն: Լավ նորություն է։ Նրանց համար, ովքեր չգիտեն, սա ժամանակային շարքերի տվյալների բազա է: Այն հիմնված է ClickHouse ճարտարապետության վրա, ClickHouse-ի իրականացման որոշ մանրամասների վրա: Օրինակ՝ MergeTree-ում, զուգահեռ հաշվարկ բոլոր հասանելի պրոցեսորային միջուկների վրա և աշխատանքի օպտիմիզացում՝ աշխատելով տվյալների բլոկների վրա, որոնք տեղադրված են պրոցեսորի քեշում:

VictoriaMetrics-ն ապահովում է տվյալների ավելի լավ սեղմում, քան ժամանակային շարքերի այլ տվյալների բազաները:

Այն մասշտաբվում է ուղղահայաց, այսինքն, դուք կարող եք ավելացնել ավելի շատ պրոցեսորներ, ավելի շատ RAM մեկ համակարգչի վրա: VictoriaMetrics-ը հաջողությամբ կօգտագործի այս հասանելի ռեսուրսները և կբարելավի գծային արտադրողականությունը:

VictoriaMetrics-ը նաև մասշտաբվում է հորիզոնական, այսինքն՝ դուք կարող եք լրացուցիչ հանգույցներ ավելացնել VictoriaMetrics կլաստերին, և դրա կատարումը կավելանա գրեթե գծային:

Ինչպես կռահեցիք, VictoriaMetrics-ը արագ տվյալների բազա է, քանի որ ես չեմ կարող գրել ուրիշներին: Եվ դա գրված է Go-ում, ուստի ես դրա մասին եմ խոսում այս հանդիպման ժամանակ:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ո՞վ գիտի, թե ինչ է ժամանակային շարքը: Նա նաև շատ մարդկանց է ճանաչում։ Ժամանակային շարքը զույգերի շարք է (timestamp, значение), որտեղ այս զույգերը դասավորված են ըստ ժամանակի։ Արժեքը լողացող կետի թիվ է՝ float64:

Յուրաքանչյուր ժամանակային շարք եզակիորեն նույնացվում է բանալիով: Ինչից է բաղկացած այս բանալին: Այն բաղկացած է բանալի-արժեք զույգերի ոչ դատարկ հավաքածուից:

Ահա ժամանակային շարքի օրինակ. Այս շարքի բանալին զույգերի ցանկն է. __name__="cpu_usage" չափիչի անունն է, instance="my-server" - սա այն համակարգիչն է, որի վրա հավաքվում է այս չափանիշը, datacenter="us-east" - սա տվյալների կենտրոնն է, որտեղ գտնվում է այս համակարգիչը:

Մենք ստացանք ժամանակային շարքի անվանումը, որը բաղկացած էր երեք բանալի-արժեք զույգերից: Այս ստեղնը համապատասխանում է զույգերի ցանկին (timestamp, value). t1, t3, t3, ..., tN - սրանք ժամանակային դրոշմանիշներ են, 10, 20, 12, ..., 15 - համապատասխան արժեքները. Սա պրոցեսորի օգտագործումն է տվյալ տողի համար տվյալ պահին:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Որտե՞ղ կարող են օգտագործվել ժամանակային շարքերը: Որևէ մեկը գաղափար ունի՞:

  • DevOps-ում կարող եք չափել պրոցեսորը, օպերատիվ հիշողությունը, ցանցը, rps-ը, սխալների քանակը և այլն:
  • IoT - մենք կարող ենք չափել ջերմաստիճանը, ճնշումը, աշխարհագրական կոորդինատները և այլ բան:
  • Նաև ֆինանսներ. մենք կարող ենք վերահսկել բոլոր տեսակի բաժնետոմսերի և արժույթների գները:
  • Բացի այդ, ժամանակային շարքերը կարող են օգտագործվել գործարաններում արտադրական գործընթացների մոնիտորինգի համար: Մենք ունենք օգտատերեր, ովքեր օգտագործում են VictoriaMetrics-ը՝ ռոբոտների համար հողմային տուրբինները վերահսկելու համար:
  • Ժամանակային շարքերը նույնպես օգտակար են տարբեր սարքերի սենսորներից տեղեկատվություն հավաքելու համար: Օրինակ, շարժիչի համար; անվադողերի ճնշումը չափելու համար; արագությունը, հեռավորությունը չափելու համար; բենզինի սպառումը չափելու համար և այլն։
  • Ժամանակային շարքերը կարող են օգտագործվել նաև ինքնաթիռների մոնիտորինգի համար: Յուրաքանչյուր ինքնաթիռ ունի սև արկղ, որը հավաքում է ժամանակային շարքեր ինքնաթիռի առողջության տարբեր պարամետրերի համար: Ժամանակային շարքերը կիրառվում են նաև օդատիեզերական արդյունաբերության մեջ։
  • Առողջապահությունը արյան ճնշումն է, զարկերակը և այլն։

Հնարավոր է, որ ավելի շատ հավելվածներ լինեն, որոնց մասին ես մոռացել եմ, բայց հուսով եմ, որ դուք հասկանում եք, որ ժամանակային շարքերը ակտիվորեն օգտագործվում են ժամանակակից աշխարհում: Իսկ դրանց օգտագործման ծավալը տարեցտարի ավելանում է։

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ինչու՞ է ձեզ անհրաժեշտ ժամանակային շարքերի տվյալների բազա: Ինչու՞ չեք կարող սովորական հարաբերական տվյալների բազա օգտագործել ժամանակային շարքերը պահելու համար:

Քանի որ ժամանակային շարքերը սովորաբար պարունակում են մեծ քանակությամբ տեղեկատվություն, որը դժվար է պահել և մշակել սովորական տվյալների բազաներում: Այդ պատճառով հայտնվեցին ժամանակային շարքերի մասնագիտացված տվյալների բազաներ։ Այս հիմքերը արդյունավետորեն պահում են միավորները (timestamp, value) տրված բանալիով։ Նրանք տրամադրում են API՝ պահված տվյալները կարդալու համար ըստ բանալիի, մեկ բանալի-արժեք զույգի, կամ մի քանի բանալի-արժեք զույգերով կամ regexp-ով: Օրինակ, դուք ցանկանում եք գտնել ձեր բոլոր ծառայությունների CPU-ի բեռնվածությունը Ամերիկայի տվյալների կենտրոնում, ապա դուք պետք է օգտագործեք այս կեղծ հարցումը:

Սովորաբար ժամանակային շարքերի տվյալների բազաները տրամադրում են հարցումների մասնագիտացված լեզուներ, քանի որ ժամանակային շարքի SQL-ն այնքան էլ հարմար չէ: Չնայած կան տվյալների բազաներ, որոնք աջակցում են SQL-ին, այն այնքան էլ հարմար չէ: Հարցման լեզուներ, ինչպիսիք են PromQL, InfluxQL, Արտահոսել, Q. Հուսով եմ, որ ինչ-որ մեկը լսել է այս լեզուներից գոնե մեկը: Շատերը հավանաբար լսել են PromQL-ի մասին: Սա Պրոմեթևսի հարցման լեզուն է:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ահա թե ինչպիսին է ժամանակակից ժամանակային շարքերի տվյալների բազայի ճարտարապետությունը՝ օգտագործելով VictoriaMetrics-ը որպես օրինակ:

Այն բաղկացած է երկու մասից. Սա պահեստավորում է շրջված ինդեքսի համար և պահեստավորում ժամանակային շարքերի արժեքների համար: Այս շտեմարաններն առանձնացված են։

Երբ տվյալների բազայում հայտնվում է նոր գրառում, մենք նախ մուտք ենք գործում շրջված ինդեքս՝ տվյալ բազմության ժամանակային շարքի նույնացուցիչը գտնելու համար: label=value տվյալ չափման համար: Մենք գտնում ենք այս նույնացուցիչը և պահպանում արժեքը տվյալների պահեստում:

Երբ հարցում է գալիս TSDB-ից տվյալներ ստանալու համար, մենք նախ գնում ենք շրջված ինդեքսին: Եկեք ամեն ինչ ստանանք timeseries_ids ռեկորդներ, որոնք համապատասխանում են այս հավաքածուին label=value. Եվ հետո մենք ստանում ենք բոլոր անհրաժեշտ տվյալները տվյալների պահեստից՝ ինդեքսավորելով timeseries_ids.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Եկեք նայենք մի օրինակ, թե ինչպես է ժամանակային շարքի տվյալների բազան մշակում մուտքային ընտրված հարցումը:

  • Առաջին հերթին նա ստանում է ամեն ինչ timeseries_ids շրջված ինդեքսից, որը պարունակում է տվյալ զույգերը label=value, կամ բավարարել տրված կանոնավոր արտահայտությունը։
  • Այնուհետև այն առբերում է տվյալների պահպանման բոլոր կետերը գտնվածների համար որոշակի ժամանակային ընդմիջումով timeseries_ids.
  • Դրանից հետո տվյալների բազան որոշակի հաշվարկներ է կատարում տվյալ տվյալների կետերի վրա՝ ըստ օգտագործողի խնդրանքի: Եվ դրանից հետո վերադարձնում է պատասխանը.

Այս շնորհանդեսում ես ձեզ կպատմեմ առաջին մասի մասին։ Սա որոնում է timeseries_ids շրջված ինդեքսով։ Երկրորդ մասի մասին, իսկ երրորդ մասը կարող եք դիտել ավելի ուշ VictoriaMetrics աղբյուրները, կամ սպասեք, մինչև ես այլ զեկույցներ պատրաստեմ :)

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Անցնենք շրջված ցուցանիշին։ Շատերը կարող են մտածել, որ սա պարզ է: Ո՞վ գիտի, թե ինչ է շրջված ինդեքսը և ինչպես է այն աշխատում: Օ՜, այլևս այդքան մարդ չկա: Փորձենք հասկանալ, թե դա ինչ է։

Դա իրականում պարզ է: Դա պարզապես բառարան է, որը քարտեզագրում է արժեքի բանալին: Ի՞նչ է բանալին: Այս զույգը label=valueՈրտեղ label и value - Սրանք տողեր են: Իսկ արժեքները մի շարք են timeseries_ids, որը ներառում է տվյալ զույգը label=value.

Շրջված ինդեքսը թույլ է տալիս արագ գտնել ամեն ինչ timeseries_ids, որոնք տվել են label=value.

Այն նաև թույլ է տալիս արագ գտնել timeseries_ids ժամանակային շարք մի քանի զույգերի համար label=value, կամ զույգերի համար label=regexp. Ինչպե՞ս է դա տեղի ունենում: Բազմության խաչմերուկը գտնելով timeseries_ids յուրաքանչյուր զույգի համար label=value.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Եկեք նայենք շրջված ինդեքսի տարբեր իրականացումներին: Սկսենք ամենապարզ միամիտ իրականացումից։ Նա այսպիսի տեսք ունի.

Ֆունկցիա getMetricIDs ստանում է տողերի ցանկ: Յուրաքանչյուր տող պարունակում է label=value. Այս ֆունկցիան վերադարձնում է ցուցակը metricIDs.

Ինչպես է դա աշխատում? Այստեղ մենք ունենք գլոբալ փոփոխական, որը կոչվում է invertedIndex. Սա սովորական բառարան է (map), որը գծագրելու է տողը՝ միջնապատերը կտրելու համար: Գիծը պարունակում է label=value.

Գործառույթի իրականացում՝ ստանալ metricIDs առաջինի համար label=value, հետո մենք անցնում ենք մնացած ամեն ինչի միջով label=value, մենք ստանում ենք այն metricIDs նրանց համար. Եվ զանգահարեք գործառույթը intersectInts, որը կքննարկվի ստորև։ Եվ այս ֆունկցիան վերադարձնում է այս ցուցակների խաչմերուկը:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ինչպես տեսնում եք, շրջված ինդեքսի իրականացումը այնքան էլ բարդ չէ: Բայց սա միամիտ իրականացում է։ Ի՞նչ թերություններ ունի այն: Միամիտ իրականացման հիմնական թերությունն այն է, որ նման շրջված ինդեքսը պահվում է RAM-ում: Հավելվածը վերագործարկելուց հետո մենք կորցնում ենք այս ցուցանիշը: Այս ցուցանիշը սկավառակի վրա չի պահվում: Նման շրջված ինդեքսը դժվար թե հարմար լինի տվյալների բազայի համար:

Երկրորդ թերությունը նույնպես կապված է հիշողության հետ։ Շրջված ինդեքսը պետք է տեղավորվի RAM-ի մեջ: Եթե ​​այն գերազանցում է RAM-ի չափը, ապա ակնհայտորեն մենք դուրս կգանք հիշողության սխալից: Եվ ծրագիրը չի աշխատի:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Այս խնդիրը կարելի է լուծել՝ օգտագործելով պատրաստի լուծումներ, ինչպիսիք են LevelDBԿամ RocksDB.

Մի խոսքով, մեզ անհրաժեշտ է տվյալների բազա, որը թույլ է տալիս արագ կատարել երեք գործողություն:

  • Առաջին գործողությունը ձայնագրությունն է ключ-значение այս տվյալների բազայում: Նա դա անում է շատ արագ, որտեղ ключ-значение կամայական տողեր են։
  • Երկրորդ գործողությունը արժեքի արագ որոնումն է՝ օգտագործելով տվյալ բանալի:
  • Եվ երրորդ գործողությունը բոլոր արժեքների արագ որոնումն է տվյալ նախածանցով:

LevelDB և RocksDB - այս տվյալների բազաները մշակվել են Google-ի և Facebook-ի կողմից: Առաջինը եկավ LevelDB-ն: Հետո ֆեյսբուքի տղաները վերցրեցին LevelDB-ն ու սկսեցին բարելավել, սարքեցին RocksDB: Այժմ գրեթե բոլոր ներքին տվյալների բազաները աշխատում են RocksDB-ում Facebook-ի ներսում, ներառյալ նրանք, որոնք փոխանցվել են RocksDB և MySQL: Նրան անվանեցին MyRocks.

Շրջված ինդեքսը կարող է իրականացվել LevelDB-ի միջոցով: Ինչպե՞ս դա անել: Մենք խնայում ենք որպես բանալի label=value. Իսկ արժեքը այն ժամանակային շարքի նույնացուցիչն է, որտեղ առկա է զույգը label=value.

Եթե ​​ունենք տրված զույգով բազմաթիվ ժամանակային շարքեր label=value, ապա այս տվյալների բազայում շատ տողեր կլինեն նույն բանալիով և տարբեր timeseries_ids. Բոլորի ցանկը ստանալու համար timeseries_ids, որոնք սկսվում են սրանով label=prefix, մենք կատարում ենք տիրույթի սկանավորում, որի համար այս տվյալների բազան օպտիմիզացված է: Այսինքն, մենք ընտրում ենք բոլոր տողերը, որոնք սկսվում են label=prefix և ստացիր անհրաժեշտը timeseries_ids.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ահա մի օրինակ, թե ինչ տեսք կունենա այն Go-ում: Մենք ունենք շրջված ինդեքս: Սա LevelDB-ն է:

Գործառույթը նույնն է, ինչ միամիտ իրականացման համար։ Գրեթե տող առ տող կրկնում է միամիտ իրականացումը։ Միակ կետն այն է, որ փոխանակ դիմելու map մենք մուտք ենք գործում շրջված ինդեքս: Մենք ստանում ենք բոլոր արժեքները առաջինի համար label=value. Հետո անցնում ենք մնացած բոլոր զույգերով label=value և ստացեք դրանց համար չափիչ ID-ների համապատասխան հավաքածուներ: Այնուհետև մենք գտնում ենք խաչմերուկը:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Թվում է, թե ամեն ինչ լավ է, բայց այս լուծումը ունի թերություններ: VictoriaMetrics-ը սկզբում ներդրեց շրջված ինդեքս՝ հիմնված LevelDB-ի վրա: Բայց ի վերջո ստիպված էի հրաժարվել դրանից։

Ինչո՞ւ։ Քանի որ LevelDB-ն ավելի դանդաղ է, քան միամիտ իրականացումը: Միամիտ իրականացման դեպքում, տրված բանալին, մենք անմիջապես առբերում ենք ամբողջ հատվածը metricIDs. Սա շատ արագ գործողություն է. ամբողջ կտորը պատրաստ է օգտագործման:

LevelDB-ում ամեն անգամ, երբ ֆունկցիա է կանչվում GetValues դուք պետք է անցնեք բոլոր տողերը, որոնք սկսվում են label=value. Եվ ստացեք արժեքը յուրաքանչյուր տողի համար timeseries_ids. Այդպիսիներից timeseries_ids հավաքեք դրանցից մի կտոր timeseries_ids. Ակնհայտ է, որ սա շատ ավելի դանդաղ է, քան սովորական քարտեզը բանալիով մուտք գործելը:

Երկրորդ թերությունն այն է, որ LevelDB-ն գրված է C-ով։ Go-ից C ֆունկցիաներ կանչելը այնքան էլ արագ չէ։ Այն տևում է հարյուրավոր նանովայրկյաններ: Սա այնքան էլ արագ չէ, քանի որ համեմատած go-ում գրված սովորական ֆունկցիայի կանչի հետ, որը տևում է 1-5 նանվայրկյան, կատարողականի տարբերությունը տասնյակ անգամ է: VictoriaMetrics-ի համար սա ճակատագրական թերություն էր :)

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Այսպիսով, ես գրեցի շրջված ինդեքսի իմ ներդրումը: Եվ նա կանչեց նրան միաձուլվել.

Mergeset-ը հիմնված է MergeTree տվյալների կառուցվածքի վրա: Այս տվյալների կառուցվածքը փոխառված է ClickHouse-ից: Ակնհայտ է, որ միաձուլումը պետք է օպտիմիզացված լինի արագ որոնման համար timeseries_ids ըստ տրված բանալի. Mergeset-ն ամբողջությամբ գրված է Go-ում: Դու կարող ես տեսնել VictoriaMetrics-ի աղբյուրները GitHub-ում. Միաձուլման իրականացումը թղթապանակում է /lib/mergeset. Դուք կարող եք փորձել պարզել, թե ինչ է կատարվում այնտեղ:

Միաձուլման API-ն շատ նման է LevelDB-ին և RocksDB-ին: Այսինքն, այն թույլ է տալիս արագ պահել այնտեղ նոր գրառումներ և արագ ընտրել գրառումները տվյալ նախածանցով:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Միաձուլման թերությունների մասին մենք կխոսենք ավելի ուշ: Հիմա եկեք խոսենք այն մասին, թե ինչ խնդիրներ են առաջացել VictoriaMetrics-ի հետ արտադրության մեջ՝ շրջված ինդեքսն իրականացնելիս։

Ինչու են նրանք առաջացել:

Առաջին պատճառն այն է, որ բարձր արագությունը. Ռուսերեն թարգմանված՝ սա ժամանակային շարքերի հաճախակի փոփոխություն է։ Սա այն դեպքում, երբ ավարտվում է ժամանակային շարքը և սկսվում է նոր շարքը, կամ սկսվում են շատ նոր ժամանակային շարքեր: Եվ դա հաճախ է պատահում:

Երկրորդ պատճառը ժամանակային շարքերի մեծ քանակությունն է։ Սկզբում, երբ մոնիտորինգը մեծ ժողովրդականություն էր վայելում, ժամանակային շարքերը փոքր էին: Օրինակ, յուրաքանչյուր համակարգչի համար անհրաժեշտ է վերահսկել պրոցեսորը, հիշողությունը, ցանցը և սկավառակի բեռնվածությունը: 4 ժամանակային շարք մեկ համակարգչի համար: Ենթադրենք, դուք ունեք 100 համակարգիչ և 400 ժամանակային շարք: Սա շատ քիչ է։

Ժամանակի ընթացքում մարդիկ հասկացան, որ կարող են չափել ավելի մանրամասն տեղեկատվություն: Օրինակ, չափեք բեռը ոչ թե ամբողջ պրոցեսորի, այլ յուրաքանչյուր պրոցեսորի միջուկի առանձին: Եթե ​​դուք ունեք 40 պրոցեսորային միջուկ, ապա դուք ունեք 40 անգամ ավելի շատ ժամանակային շարք պրոցեսորի ծանրաբեռնվածությունը չափելու համար:

Բայց սա դեռ ամենը չէ։ Յուրաքանչյուր պրոցեսորի միջուկը կարող է ունենալ մի քանի վիճակ, օրինակ՝ անգործուն, երբ այն անգործուն է: Եվ նաև աշխատեք օգտագործողի տարածքում, աշխատեք միջուկի տարածքում և այլ վիճակներում: Եվ յուրաքանչյուր այդպիսի վիճակ կարող է չափվել նաև որպես առանձին ժամանակային շարք։ Սա լրացուցիչ ավելացնում է տողերի քանակը 7-8 անգամ:

Մեկ մետրից մենք ստացանք 40 x 8 = 320 չափումներ ընդամենը մեկ համակարգչի համար: Բազմապատկենք 100-ով, 32-ի փոխարեն ստանում ենք 000։

Հետո եկավ Կուբերնետեսը: Եվ դա ավելի վատացավ, քանի որ Kubernetes-ը կարող է հյուրընկալել բազմաթիվ տարբեր ծառայություններ: Յուրաքանչյուր ծառայություն Kubernetes-ում բաղկացած է բազմաթիվ պատյաններից: Եվ այս ամենը պետք է վերահսկվի։ Բացի այդ, մենք ունենք ձեր ծառայությունների նոր տարբերակների մշտական ​​տեղակայում: Յուրաքանչյուր նոր տարբերակի համար պետք է ստեղծվեն նոր ժամանակային շարքեր: Արդյունքում ժամանակային շարքերի թիվը երկրաչափականորեն աճում է, և մենք բախվում ենք մեծ թվով ժամանակային շարքերի խնդրին, որը կոչվում է բարձր կարդինալություն։ VictoriaMetrics-ը հաջողությամբ հաղթահարում է այն՝ համեմատած այլ ժամանակային տվյալների բազաների հետ:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Եկեք ավելի սերտ նայենք բարձր շեղումների արագությանը: Ինչն է առաջացնում արտադրության բարձր անկման արագություն: Քանի որ պիտակների և պիտակների որոշ իմաստներ անընդհատ փոխվում են:

Օրինակ, վերցրեք Kubernetes-ը, որն ունի հայեցակարգը deployment, այսինքն՝ երբ թողարկվի ձեր հավելվածի նոր տարբերակը: Չգիտես ինչու, Kubernetes-ի մշակողները որոշեցին պիտակի վրա ավելացնել տեղակայման ID-ն:

Սա ինչի՞ հանգեցրեց։ Ավելին, յուրաքանչյուր նոր տեղակայման հետ բոլոր հին ժամանակային շարքերն ընդհատվում են, և դրանց փոխարեն նոր ժամանակային շարքերը սկսվում են նոր պիտակի արժեքով: deployment_id. Նման տողերը կարող են լինել հարյուր հազարավոր և նույնիսկ միլիոնավոր:

Այս ամենի հետ կապված կարևորն այն է, որ ժամանակային շարքերի ընդհանուր թիվն աճում է, բայց ներկայումս ակտիվ գործող և տվյալներ ստացող ժամանակային շարքերի թիվը մնում է անփոփոխ: Այս վիճակը կոչվում է բարձր շեղման արագություն:

Շարժման բարձր արագության հիմնական խնդիրն այն է, որ ապահովվի մշտական ​​որոնման արագություն բոլոր ժամանակային շարքերի համար տվյալ պիտակների հավաքածուի համար որոշակի ժամանակային ընդմիջումով: Սովորաբար սա վերջին ժամի կամ վերջին օրվա ժամանակային ընդմիջումն է:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ինչպե՞ս լուծել այս խնդիրը: Ահա առաջին տարբերակը. Սա ժամանակի ընթացքում շրջված ինդեքսը անկախ մասերի բաժանելու համար է: Այսինքն՝ որոշակի ժամանակային ընդմիջում է անցնում, մենք ավարտում ենք աշխատանքը ընթացիկ շրջված ինդեքսով։ Եվ ստեղծեք նոր շրջված ինդեքս: Անցնում է մեկ այլ ժամանակային ինտերվալ, մենք ստեղծում ենք մեկ ուրիշը և մյուսը:

Եվ այս շրջված ինդեքսներից նմուշառելիս մենք գտնում ենք շրջված ինդեքսների մի շարք, որոնք ընկնում են տվյալ միջակայքում։ Եվ, համապատասխանաբար, այնտեղից ընտրում ենք ժամանակային շարքի id-ն։

Սա խնայում է ռեսուրսները, քանի որ մենք չպետք է նայենք այն մասերին, որոնք չեն մտնում տվյալ միջակայքում: Այսինքն, սովորաբար, եթե մենք ընտրում ենք տվյալներ վերջին ժամի համար, ապա նախորդ ժամանակային ընդմիջումներով մենք բաց ենք թողնում հարցումները:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Այս խնդիրը լուծելու մեկ այլ տարբերակ կա. Սա յուրաքանչյուր օրվա համար պահելու է ժամանակային շարքերի նույնականացման առանձին ցուցակ, որոնք տեղի են ունեցել այդ օրը:

Այս լուծման առավելությունը նախորդ լուծման նկատմամբ այն է, որ մենք չենք կրկնօրինակում ժամանակային շարքի տեղեկատվությունը, որը ժամանակի ընթացքում չի անհետանում: Նրանք մշտապես ներկա են և չեն փոխվում։

Թերությունն այն է, որ նման լուծումն ավելի դժվար է իրականացնել և ավելի դժվար է կարգաբերել: Եվ VictoriaMetrics-ն ընտրեց այս լուծումը: Պատմականորեն այսպես է եղել. Այս լուծումը նույնպես լավ է կատարում նախորդի համեմատ: Որովհետև այս լուծումը չի իրականացվել այն պատճառով, որ անհրաժեշտ է կրկնօրինակել տվյալներ յուրաքանչյուր բաժանման մեջ ժամանակային շարքերի համար, որոնք չեն փոխվում, այսինքն՝ ժամանակի ընթացքում չեն անհետանում: VictoriaMetrics-ը հիմնականում օպտիմիզացված էր սկավառակի տարածության սպառման համար, իսկ նախորդ ներդրումը վատթարացրեց սկավառակի տարածության սպառումը: Բայց այս իրականացումը ավելի հարմար է սկավառակի տարածության սպառումը նվազագույնի հասցնելու համար, ուստի այն ընտրվեց:

Ես ստիպված էի կռվել նրա հետ: Պայքարն այն էր, որ այս իրականացման մեջ դեռ պետք է շատ ավելի մեծ թիվ ընտրել timeseries_ids տվյալների համար, քան երբ շրջված ինդեքսը ժամանակի բաժանված է:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ինչպե՞ս լուծեցինք այս խնդիրը: Մենք դա լուծեցինք օրիգինալ ձևով՝ մեկ նույնացուցիչի փոխարեն յուրաքանչյուր շրջված ինդեքսում մուտքագրելով մի քանի ժամանակային շարքի նույնացուցիչներ: Այսինքն՝ մենք բանալի ունենք label=value, որը տեղի է ունենում յուրաքանչյուր ժամանակային շարքում: Եվ հիմա մենք խնայում ենք մի քանիսը timeseries_ids մեկ մուտքի մեջ.

Ահա մի օրինակ. Նախկինում մենք ունեինք N մուտք, բայց հիմա ունենք մեկ մուտք, որի նախածանցը նույնն է, ինչ բոլոր մյուսները: Նախորդ մուտքի համար արժեքը պարունակում է բոլոր ժամանակային շարքերի ID-ները:

Սա հնարավորություն տվեց մեծացնել նման շրջված ինդեքսի սկանավորման արագությունը մինչև 10 անգամ։ Եվ դա մեզ թույլ տվեց նվազեցնել հիշողության սպառումը քեշի համար, քանի որ այժմ մենք պահում ենք տողը label=value միայն մեկ անգամ քեշում միասին N անգամ: Եվ այս գիծը կարող է մեծ լինել, եթե երկար տողեր եք պահում ձեր պիտակներում և պիտակներում, որոնք Kubernetes-ը սիրում է խցկել այնտեղ:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Շրջված ինդեքսի վրա որոնումը արագացնելու մեկ այլ տարբերակ է շարադրումը: Մեկի փոխարեն մի քանի շրջված ինդեքսների ստեղծում և դրանց միջև տվյալների բաշխում բանալիով: Սա հավաքածու է key=value գոլորշու. Այսինքն՝ մենք ստանում ենք մի քանի անկախ շրջված ինդեքսներ, որոնք կարող ենք զուգահեռ հարցումներ կատարել մի քանի պրոցեսորների վրա։ Նախորդ իրականացումները թույլ էին տալիս գործել միայն մեկ պրոցեսորային ռեժիմում, այսինքն՝ տվյալների սկանավորում միայն մեկ միջուկի վրա: Այս լուծումը թույլ է տալիս սկանավորել տվյալներ միանգամից մի քանի միջուկների վրա, ինչպես սիրում է անել ClickHouse-ը: Սա այն է, ինչ մենք նախատեսում ենք իրականացնել։

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Հիմա վերադառնանք մեր ոչխարներին՝ հատման ֆունկցիային timeseries_ids. Եկեք դիտարկենք, թե ինչ իրականացումներ կարող են լինել։ Այս գործառույթը թույլ է տալիս գտնել timeseries_ids տվյալ հավաքածուի համար label=value.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Առաջին տարբերակը միամիտ իրականացում է։ Երկու բնադրված օղակ: Այստեղ մենք ստանում ենք ֆունկցիայի մուտքագրումը intersectInts երկու շերտ - a и b. Ելքի ժամանակ այն պետք է մեզ վերադարձնի այս հատվածների խաչմերուկը:

Միամիտ իրականացումն այսպիսի տեսք ունի. Մենք կրկնում ենք բոլոր արժեքները հատվածից a, այս օղակի ներսում մենք անցնում ենք հատվածի բոլոր արժեքները b. Եվ մենք համեմատում ենք դրանք: Եթե ​​համընկնում են, ուրեմն խաչմերուկ ենք գտել։ Եվ պահպանեք այն result.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Որո՞նք են թերությունները: Քառակուսային բարդությունը նրա հիմնական թերությունն է: Օրինակ, եթե ձեր չափերը կտոր են a и b միանգամից մեկ միլիոն, ապա այս ֆունկցիան երբեք ձեզ պատասխան չի վերադարձնի: Քանի որ այն պետք է կատարի մեկ տրիլիոն կրկնություններ, ինչը շատ է նույնիսկ ժամանակակից համակարգիչների համար:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Երկրորդ իրականացումը հիմնված է քարտեզի վրա: Մենք ստեղծում ենք քարտեզ. Մենք այս քարտեզի մեջ դնում ենք հատվածից բոլոր արժեքները a. Այնուհետև մենք անցնում ենք մի կտոր առանձին օղակով b. Եվ մենք ստուգում ենք, թե արդյոք այս արժեքը կտորից է b քարտեզի վրա։ Եթե ​​այն կա, ապա ավելացրեք այն արդյունքին։

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Որո՞նք են օգուտները: Առավելությունն այն է, որ կա միայն գծային բարդություն: Այսինքն, գործառույթը շատ ավելի արագ կկատարվի ավելի մեծ կտորների համար: Մի միլիոն չափսի հատվածի համար այս ֆունկցիան կկատարվի 2 միլիոն կրկնումով՝ ի տարբերություն նախորդ ֆունկցիայի տրիլիոն կրկնությունների:

Բացասական կողմն այն է, որ այս ֆունկցիան ավելի շատ հիշողություն է պահանջում այս քարտեզը ստեղծելու համար:

Երկրորդ թերությունը հաշինգի մեծ ծախսն է: Այս թերությունն այնքան էլ ակնհայտ չէ։ Եվ մեզ համար դա նույնպես այնքան էլ ակնհայտ չէր, ուստի սկզբում VictoriaMetrics-ում խաչմերուկի իրականացումը քարտեզի միջոցով էր։ Բայց հետո պրոֆիլավորումը ցույց տվեց, որ հիմնական պրոցեսորի ժամանակը ծախսվում է քարտեզի վրա գրելու և այս քարտեզում արժեքի առկայությունը ստուգելու համար:

Ինչու՞ է պրոցեսորի ժամանակը վատնում այս վայրերում: Քանի որ Go-ն այս տողերի վրա կատարում է հեշինգի գործողություն: Այսինքն, այն հաշվարկում է բանալու հեշը, որպեսզի հետո մուտք գործի այն HashMap-ի տվյալ ինդեքսով: Հեշի հաշվարկման գործողությունն ավարտվում է տասնյակ նանովայրկյաններով: Սա դանդաղ է VictoriaMetrics-ի համար:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ես որոշեցի կիրառել բիթսեթ, որը օպտիմիզացված է հատուկ այս գործի համար: Ահա թե ինչ տեսք ունի այժմ երկու շերտի խաչմերուկը: Այստեղ մենք ստեղծում ենք բիթերի հավաքածու: Մենք դրան ավելացնում ենք տարրեր առաջին կտորից։ Այնուհետեւ մենք ստուգում ենք այս տարրերի առկայությունը երկրորդ շերտում: Եվ դրանք ավելացրեք արդյունքին: Այսինքն՝ գրեթե չի տարբերվում նախորդ օրինակից։ Այստեղ միակ բանն այն է, որ մենք քարտեզի հասանելիությունը փոխարինեցինք հատուկ գործառույթներով add и has.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Առաջին հայացքից թվում է, որ սա պետք է ավելի դանդաղ աշխատի, եթե նախկինում այնտեղ օգտագործվում էր ստանդարտ քարտեզ, այնուհետև կանչվում են որոշ այլ գործառույթներ, բայց պրոֆիլավորումը ցույց է տալիս, որ այս բանը 10 անգամ ավելի արագ է աշխատում, քան ստանդարտ քարտեզը VictoriaMetrics-ի դեպքում:

Բացի այդ, այն շատ ավելի քիչ հիշողություն է օգտագործում՝ համեմատած քարտեզի իրականացման հետ: Քանի որ մենք այստեղ ութ բայթ արժեքների փոխարեն բիթ ենք պահում:

Այս իրականացման թերությունն այն է, որ այն այնքան էլ ակնհայտ չէ, ոչ մանրուք:

Մեկ այլ թերություն, որը շատերը կարող են չնկատել, այն է, որ այս իրականացումը որոշ դեպքերում կարող է լավ չաշխատել: Այսինքն՝ այն օպտիմիզացված է կոնկրետ դեպքի համար՝ VictoriaMetrics-ի ժամանակային շարքի ID-ների հատման դեպքի համար։ Սա չի նշանակում, որ այն հարմար է բոլոր դեպքերի համար։ Եթե ​​այն սխալ օգտագործվի, մենք կստանանք ոչ թե կատարողականի բարձրացում, այլ հիշողության պակասի սխալ և կատարողականի դանդաղում:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Դիտարկենք այս կառույցի իրականացումը։ Եթե ​​ուզում եք նայել, այն գտնվում է VictoriaMetrics-ի աղբյուրներում՝ թղթապանակում lib/uint64set. Այն օպտիմիզացված է հատուկ VictoriaMetrics գործի համար, որտեղ timeseries_id 64-բիթանոց արժեք է, որտեղ առաջին 32 բիթերը հիմնականում հաստատուն են, և միայն վերջին 32 բիթերն են փոխվում:

Տվյալների այս կառուցվածքը չի պահվում սկավառակի վրա, այն աշխատում է միայն հիշողության մեջ:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ահա նրա API-ն: Դա այնքան էլ բարդ չէ: API-ն հատուկ հարմարեցված է VictoriaMetrics-ի օգտագործման կոնկրետ օրինակին: Այսինքն՝ այստեղ ավելորդ գործառույթներ չկան։ Ահա այն գործառույթները, որոնք բացահայտորեն օգտագործվում են VictoriaMetrics-ի կողմից:

Գործառույթներ կան add, որն ավելացնում է նոր արժեքներ։ Գործառույթ կա has, որը ստուգում է նոր արժեքների առկայությունը: Եվ կա գործառույթ del, որը վերացնում է արժեքները: Կա օգնական գործառույթ len, որը վերադարձնում է հավաքածուի չափը: Գործառույթ clone շատ է կլոնավորում: Եվ գործառույթ appendto փոխակերպում է այս հավաքածուն կտորի timeseries_ids.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ահա թե ինչ տեսք ունի այս տվյալների կառուցվածքի իրականացումը: հավաքածուն ունի երկու տարր.

  • ItemsCount օգնական դաշտ է՝ հավաքածուի տարրերի քանակը արագ վերադարձնելու համար: Դա հնարավոր կլիներ անել առանց այս օժանդակ դաշտի, բայց այն պետք է ավելացվեր այստեղ, քանի որ VictoriaMetrics-ը հաճախ հարցնում է բիթերի երկարությունը իր ալգորիթմներում:

  • Երկրորդ դաշտն է buckets. Սա մի հատված է կառուցվածքից bucket32. Յուրաքանչյուր կառույց պահում է hi դաշտ. Սրանք վերին 32 բիթերն են: Եվ երկու կտոր - b16his и buckets - ից bucket16 կառույցները։

Այստեղ պահվում են 16-բիթանոց կառուցվածքի երկրորդ մասի վերին 64 բիթերը: Եվ այստեղ բիթերը պահվում են յուրաքանչյուր բայթի ստորին 16 բիթերի համար:

Bucket64 կազմված է զանգվածից uint64. Երկարությունը հաշվարկվում է այս հաստատունների միջոցով: Մեկում bucket16 առավելագույնը կարող է պահվել 2^16=65536 քիչ. Եթե ​​սա բաժանեք 8-ի, ապա դա 8 կիլոբայթ է: Եթե ​​կրկին բաժանեք 8-ի, ապա դա կլինի 1000 uint64 իմաստը. Այն է Bucket16 – սա մեր 8 կիլոբայթանոց կառուցվածքն է:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Եկեք նայենք, թե ինչպես է իրականացվում այս կառուցվածքի նոր արժեք ավելացնելու մեթոդներից մեկը:

Ամեն ինչ սկսվում է նրանից uint64 իմաստներ. Մենք հաշվում ենք վերին 32 բիթը, հաշվում ենք ստորին 32 բիթը։ Եկեք անցնենք ամեն ինչի միջով buckets. Մենք համեմատում ենք յուրաքանչյուր դույլի վերին 32 բիթերը ավելացված արժեքի հետ: Իսկ եթե դրանք համընկնում են, ապա մենք անվանում ենք ֆունկցիա add b32 կառուցվածքում buckets. Եվ այնտեղ ավելացրեք ստորին 32 բիթերը: Իսկ եթե վերադառնար true, ապա սա նշանակում է, որ մենք այնտեղ նման արժեք ենք ավելացրել ու նման արժեք չենք ունեցել։ Եթե ​​վերադառնա false, ապա նման իմաստ արդեն կար. Այնուհետև մենք ավելացնում ենք կառուցվածքի տարրերի քանակը:

Եթե ​​մենք չենք գտել ձեզ անհրաժեշտը bucket պահանջվող բարձր արժեքով, այնուհետև մենք կանչում ենք ֆունկցիան addAlloc, որը կարտադրի նորը bucket, ավելացնելով այն դույլի կառուցվածքին:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Սա գործառույթի իրականացումն է b32.add. Դա նման է նախորդ իրականացմանը։ Մենք հաշվարկում ենք ամենակարևոր 16 բիթը, ամենաքիչ նշանակալից 16 բիթը:

Այնուհետև մենք անցնում ենք բոլոր վերին 16 բիթերը: Մենք գտնում ենք լուցկիներ: Իսկ եթե համընկնում է, անվանում ենք ավելացնել մեթոդը, որը կդիտարկենք հաջորդ էջում bucket16.

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Եվ ահա ամենացածր մակարդակը, որը պետք է հնարավորինս օպտիմալացնել։ Մենք հաշվարկում ենք uint64 id արժեքը հատվածի բիթով և նաև bitmask. Սա դիմակ է տվյալ 64-բիթանոց արժեքի համար, որը կարող է օգտագործվել այս բիթը ստուգելու կամ սահմանելու համար: Մենք ստուգում ենք՝ արդյոք այս բիթը դրված է, և սահմանում ենք այն և վերադարձնում ներկայությունը: Սա մեր իրականացումն է, որը թույլ է տվել մեզ արագացնել ժամանակային շարքերի հատվող ID-ների աշխատանքը 10 անգամ՝ համեմատած սովորական քարտեզների հետ։

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Բացի այս օպտիմալացումից, VictoriaMetrics-ն ունի բազմաթիվ այլ օպտիմալացումներ: Այս օպտիմալացումների մեծ մասն ավելացվել է ինչ-որ պատճառով, բայց արտադրության մեջ ծածկագիրը պրոֆիլավորելուց հետո:

Սա է օպտիմալացման հիմնական կանոնը. մի ավելացրեք օպտիմալացում՝ ենթադրելով, որ այստեղ նեղություն է լինելու, որովհետև կարող է պարզվել, որ այնտեղ խոչընդոտ չի լինի: Օպտիմալացումը սովորաբար վատացնում է կոդի որակը: Հետևաբար, արժե օպտիմալացնել միայն պրոֆիլավորումից հետո և գերադասելի է արտադրության մեջ, որպեսզի դրանք իրական տվյալներ լինեն։ Եթե ​​որևէ մեկին հետաքրքրում է, կարող եք նայել VictoriaMetrics-ի սկզբնական կոդը և ուսումնասիրել այնտեղ առկա այլ օպտիմալացումներ:

Գնացեք օպտիմալացում VictoriaMetrics-ում: Ալեքսանդր Վալյալկին

Ես մի հարց ունեմ bitset-ի մասին. Շատ նման է C++ վեկտորային bool իրականացմանը, օպտիմիզացված բիթերի հավաքածուն: Այդտեղի՞ց եք վերցրել իրականացումը։

Ոչ, ոչ այնտեղից: Այս բիթսեթն իրականացնելիս ես առաջնորդվել եմ այս ID-ների ժամանակաշարերի կառուցվածքի իմացությամբ, որոնք օգտագործվում են VictoriaMetrics-ում: Եվ նրանց կառուցվածքն այնպիսին է, որ վերին 32 բիթերը հիմնականում հաստատուն են: Ստորին 32 բիթները ենթակա են փոփոխության: Որքան ցածր է բիթը, այնքան ավելի հաճախ այն կարող է փոխվել: Հետևաբար, այս իրականացումը հատուկ օպտիմիզացված է այս տվյալների կառուցվածքի համար: C++-ի իրականացումը, որքան գիտեմ, օպտիմիզացված է ընդհանուր գործի համար։ Եթե ​​դուք օպտիմիզացնում եք ընդհանուր գործի համար, դա նշանակում է, որ այն առավել օպտիմալը չի ​​լինի կոնկրետ դեպքի համար:

Խորհուրդ եմ տալիս դիտել նաև Ալեքսեյ Միլովիդի ռեպորտաժը։ Մոտ մեկ ամիս առաջ նա խոսեց ClickHouse-ում կոնկրետ մասնագիտությունների օպտիմալացման մասին։ Նա պարզապես ասում է, որ ընդհանուր դեպքում C++-ի ներդրումը կամ որևէ այլ իրականացում հարմարեցված է հիվանդանոցում միջինը լավ աշխատելու համար: Այն կարող է ավելի վատ գործել, քան գիտելիքին հատուկ իրականացումը, ինչպիսին մերն է, որտեղ մենք գիտենք, որ լավագույն 32 բիթերը հիմնականում հաստատուն են:

Ես երկրորդ հարց ունեմ. Ո՞րն է հիմնարար տարբերությունը InfluxDB-ից:

Շատ հիմնարար տարբերություններ կան. Ինչ վերաբերում է կատարողականին և հիշողության սպառմանը, թեստերում InfluxDB-ն ցույց է տալիս 10 անգամ ավելի շատ հիշողության սպառում բարձր կարդինալության ժամանակային շարքերի համար, երբ դրանք շատ են, օրինակ՝ միլիոններ: Օրինակ, VictoriaMetrics-ը սպառում է 1 ԳԲ յուրաքանչյուր միլիոն ակտիվ տողում, մինչդեռ InfluxDB-ն սպառում է 10 ԳԲ: Եվ դա մեծ տարբերություն է:

Երկրորդ հիմնարար տարբերությունն այն է, որ InfluxDB-ն ունի հարցման տարօրինակ լեզուներ՝ Flux և InfluxQL: համեմատ ժամանակային շարքերի հետ աշխատելու համար այնքան էլ հարմար չեն PromQL, որն աջակցում է VictoriaMetrics-ը: PromQL-ը Պրոմեթևսի հարցումների լեզու է:

Եվ ևս մեկ տարբերություն այն է, որ InfluxDB-ն ունի մի փոքր տարօրինակ տվյալների մոդել, որտեղ յուրաքանչյուր տող կարող է պահել մի քանի դաշտեր տարբեր պիտակների հավաքածուով: Այս տողերը հետագայում բաժանվում են տարբեր աղյուսակների: Այս լրացուցիչ բարդությունները բարդացնում են հետագա աշխատանքը այս տվյալների բազայի հետ: Դժվար է աջակցել ու հասկանալ։

VictoriaMetrics-ում ամեն ինչ շատ ավելի պարզ է: Այնտեղ յուրաքանչյուր ժամանակային շարք բանալի-արժեք է: Արժեքը միավորների մի շարք է. (timestamp, value), իսկ բանալին հավաքածուն է label=value. Չկա տարանջատում դաշտերի և չափումների միջև: Այն թույլ է տալիս ընտրել ցանկացած տվյալ և այնուհետև միավորել, ավելացնել, հանել, բազմապատկել, բաժանել, ի տարբերություն InfluxDB-ի, որտեղ տարբեր տողերի միջև հաշվարկները դեռևս չեն իրականացվում, որքան ես գիտեմ: Եթե ​​նույնիսկ դրանք իրականացվեն, դժվար է, պետք է շատ կոդ գրել։

Ես մի ճշտող հարց ունեմ. Ես ճի՞շտ հասկացա, որ ինչ-որ խնդիր կար, որի մասին խոսեցիր, որ այս շրջված ինդեքսը չի տեղավորվում հիշողության մեջ, ուրեմն այնտեղ բաժանում կա։

Նախ, ես ցույց տվեցի շրջված ինդեքսի միամիտ իրականացումը ստանդարտ Go քարտեզի վրա: Այս իրականացումը հարմար չէ տվյալների բազաների համար, քանի որ այս շրջված ինդեքսը չի պահվում սկավառակի վրա, և տվյալների բազան պետք է պահվի սկավառակի վրա, որպեսզի այս տվյալները հասանելի մնան վերագործարկման ժամանակ: Այս իրականացման դեպքում, երբ վերագործարկեք հավելվածը, ձեր շրջված ինդեքսը կվերանա: Եվ դուք կկորցնեք մուտքը դեպի բոլոր տվյալները, քանի որ չեք կարողանա գտնել դրանք:

Բարեւ Ձեզ! Շնորհակալություն զեկույցի համար: Իմ անունը Պավել է։ Ես Wildberries-ից եմ: Ես ձեզ մի քանի հարց ունեմ: Հարց առաջին. Կարծում եք, որ եթե ձեր հավելվածի ճարտարապետությունը կառուցելիս ընտրեիք այլ սկզբունք և ժամանակի ընթացքում բաժանեիք տվյալները, ապա գուցե կարողանայիք տվյալների հատում կատարել որոնման ժամանակ՝ հիմնվելով միայն այն փաստի վրա, որ մեկ բաժանումը պարունակում է տվյալներ մեկի համար: ժամանակահատվածում, այսինքն՝ մեկ ժամանակամիջոցում, և դուք ստիպված չեք լինի անհանգստանալ այն փաստի համար, որ ձեր կտորները տարբեր կերպ են ցրված: Հարց թիվ 2 - քանի որ դուք նմանատիպ ալգորիթմ եք իրականացնում բիթսեթով և մնացած ամեն ինչով, ապա միգուցե փորձե՞լ եք օգտագործել պրոցեսորի հրահանգները: Գուցե դուք փորձե՞լ եք նման օպտիմալացումներ։

Երկրորդին անմիջապես կպատասխանեմ. Մենք դեռ չենք հասել այդ կետին: Բայց եթե պետք լինի, մենք այնտեղ կհասնենք։ Իսկ առաջինը՝ ո՞րն էր հարցը։

Դուք քննարկել եք երկու սցենար. Եվ ասացին, որ ընտրել են երկրորդը՝ ավելի բարդ իրականացումով։ Իսկ առաջինը չնախընտրեցին, որտեղ տվյալները բաժանված են ժամանակով։

Այո՛։ Առաջին դեպքում ինդեքսի ընդհանուր ծավալը կլինի ավելի մեծ, քանի որ յուրաքանչյուր բաժանման մեջ մենք պետք է կրկնօրինակ տվյալներ պահենք այն ժամանակային շարքերի համար, որոնք շարունակվում են այս բոլոր բաժինների միջով: Եվ եթե ձեր ժամանակային շարքի շեղման արագությունը փոքր է, այսինքն՝ անընդհատ օգտագործվում են նույն շարքերը, ապա առաջին դեպքում մենք շատ ավելի կկորցնենք սկավառակի զբաղեցրած տարածության չափով, քան երկրորդ դեպքում:

Եվ այսպես, այո, ժամանակի բաժանումը լավ տարբերակ է: Պրոմեթևսն օգտագործում է այն: Սակայն Պրոմեթևսն ունի մեկ այլ թերություն. Տվյալների այս կտորները միաձուլելիս այն պետք է հիշողության մեջ պահի բոլոր պիտակների և ժամանակային շարքերի մետա տեղեկատվությունը: Հետևաբար, եթե տվյալների մասերը, որոնք այն միավորում է, մեծ են, ապա հիշողության սպառումը միաձուլման ժամանակ շատ է աճում, ի տարբերություն VictoriaMetrics-ի: Միաձուլման ժամանակ VictoriaMetrics-ն ընդհանրապես հիշողություն չի սպառում, սպառվում է ընդամենը մի քանի կիլոբայթ՝ անկախ տվյալների միավորված մասերի չափից:

Ալգորիթմը, որը դուք օգտագործում եք, օգտագործում է հիշողություն: Այն նշում է ժամանակային շարքի պիտակները, որոնք արժեքներ են պարունակում: Եվ այս կերպ դուք ստուգում եք զուգակցված ներկայությունը տվյալների մի զանգվածում և մյուսում: Եվ դուք հասկանում եք՝ խաչմերուկը տեղի է ունեցել, թե ոչ։ Սովորաբար, տվյալների բազաները իրականացնում են կուրսորներ և կրկնողներ, որոնք պահում են իրենց ընթացիկ բովանդակությունը և անցնում են տեսակավորված տվյալների միջով՝ այս գործողությունների պարզ բարդության պատճառով:

Ինչու՞ մենք չենք օգտագործում կուրսորները տվյալների անցման համար:

Այո:

Մենք պահպանում ենք տեսակավորված տողերը LevelDB կամ mergeset-ում: Մենք կարող ենք շարժել կուրսորը և գտնել խաչմերուկը: Ինչու չենք օգտագործում այն: Քանի որ դա դանդաղ է: Քանի որ կուրսորները նշանակում են, որ յուրաքանչյուր տողի համար անհրաժեշտ է ֆունկցիա կանչել: Ֆունկցիայի կանչը 5 նանվայրկյան է: Իսկ եթե ունես 100 տող, ապա ստացվում է, որ մենք կես վայրկյան ենք ծախսում պարզապես ֆունկցիան կանչելու համար։

Նման բան կա, այո։ Եվ իմ վերջին հարցը. Հարցը կարող է մի փոքր տարօրինակ հնչել. Ինչու՞ հնարավոր չէ կարդալ բոլոր անհրաժեշտ ագրեգատները տվյալների ժամանման պահին և պահպանել դրանք անհրաժեշտ ձևով: Ինչու՞ հսկայական ծավալներ խնայել որոշ համակարգերում, ինչպիսիք են VictoriaMetrics-ը, ClickHouse-ը և այլն, և հետո շատ ժամանակ ծախսել դրանց վրա:

Ես օրինակ բերեմ, որպեսզի ավելի պարզ լինի. Եկեք ասենք, թե ինչպես է աշխատում փոքրիկ խաղալիք արագաչափը: Այն գրանցում է ձեր անցած ճանապարհը՝ անընդհատ ավելացնելով այն մեկ արժեքի, իսկ երկրորդը՝ ժամանակը: Եվ բաժանում է. Եվ ստանում է միջին արագություն: Դուք կարող եք անել նույն բանը: Ավելացրեք բոլոր անհրաժեշտ փաստերը թռիչքի ժամանակ:

Լավ, ես հասկանում եմ հարցը։ Ձեր օրինակն իր տեղն ունի։ Եթե ​​գիտեք, թե ինչ ագրեգատներ են ձեզ անհրաժեշտ, ապա սա լավագույն իրականացումն է: Բայց խնդիրն այն է, որ մարդիկ պահպանում են այս չափումները, որոշ տվյալներ ClickHouse-ում, և նրանք դեռ չգիտեն, թե ինչպես են դրանք համախմբելու և զտելու ապագայում, ուստի պետք է պահպանեն բոլոր չմշակված տվյալները: Բայց եթե գիտեք, որ պետք է ինչ-որ բան հաշվարկել միջին հաշվով, ապա ինչո՞ւ չհաշվել այն՝ այնտեղ մի փունջ հում արժեքներ պահելու փոխարեն: Բայց սա միայն այն դեպքում, եթե դուք հստակ գիտեք, թե ինչ է ձեզ անհրաժեշտ:

Ի դեպ, ժամանակային շարքերի պահպանման տվյալների բազաները աջակցում են ագրեգատների հաշվմանը։ Օրինակ, Պրոմեթեւսն աջակցում է ձայնագրման կանոններ. Այսինքն, դա կարելի է անել, եթե դուք գիտեք, թե ինչ միավորներ ձեզ անհրաժեշտ կլինեն: VictoriaMetrics-ը դեռ չունի սա, բայց սովորաբար դրան նախորդում է Պրոմեթևսը, որում դա կարելի է անել վերակոդավորման կանոններում։

Օրինակ, իմ նախորդ աշխատանքում ես պետք է հաշվեի վերջին մեկ ժամվա ընթացքում լոգարիթմական պատուհանի իրադարձությունների քանակը: Խնդիրն այն է, որ ես ստիպված էի Go-ում կատարել մաքսային իրականացում, այսինքն՝ ծառայություն այս բանը հաշվելու համար։ Այս ծառայությունը, ի վերջո, ոչ տրիվիալ էր, քանի որ դժվար է հաշվարկել։ Իրականացումը կարող է լինել պարզ, եթե ձեզ անհրաժեշտ է հաշվել որոշ ագրեգատներ ֆիքսված ժամանակային ընդմիջումներով: Եթե ​​ցանկանում եք հաշվել իրադարձությունները լոգարիթմական պատուհանում, ապա դա այնքան էլ պարզ չէ, որքան թվում է: Կարծում եմ՝ սա դեռ չի ներդրվել ClickHouse-ում կամ ժամանակագրական տվյալների բազաներում, քանի որ դժվար է իրականացնել։

Եվ ևս մեկ հարց. Մենք ուղղակի խոսում էինք միջինացման մասին, և ես հիշեցի, որ ժամանակին կար այնպիսի բան, ինչպիսին Graphite-ն էր՝ Carbon backend-ով: Եվ նա գիտեր, թե ինչպես կարելի է նոսրացնել հին տվյալները, այսինքն՝ թողնել րոպեում մեկ միավոր, ժամում մեկ կետ և այլն։ Սկզբունքորեն, սա բավականին հարմար է, եթե մեզ անհրաժեշտ են հում տվյալներ, համեմատաբար մեկ ամսվա համար, և մնացած ամեն ինչ կարող է։ նոսրանալ. Բայց Prometheus-ը և VictoriaMetrics-ը չեն աջակցում այս գործառույթը: Նախատեսվու՞մ է աջակցել դրան։ Եթե ​​ոչ, ինչո՞ւ ոչ։

Շնորհակալություն հարցի համար: Մեր օգտատերերը պարբերաբար տալիս են այս հարցը։ Նրանք հարցնում են, թե երբ կավելացնենք աջակցություն կրճատման համար: Այստեղ մի քանի խնդիրներ կան. Նախ, յուրաքանչյուր օգտվող հասկանում է downsampling ինչ-որ այլ բան. ինչ-որ մեկը ցանկանում է ստանալ որևէ կամայական կետ տվյալ ինտերվալի վրա, ինչ-որ մեկը ցանկանում է առավելագույն, նվազագույն, միջին արժեքներ: Եթե ​​շատ համակարգեր գրում են տվյալներ ձեր տվյալների բազայում, ապա դուք չեք կարող դրանք միավորել: Հնարավոր է, որ յուրաքանչյուր համակարգ պահանջում է տարբեր նոսրացում: Իսկ դա դժվար է իրականացնել։

Եվ երկրորդն այն է, որ VictoriaMetrics-ը, ինչպես ClickHouse-ը, օպտիմիզացված է մեծ քանակությամբ չմշակված տվյալների վրա աշխատելու համար, այնպես որ այն կարող է մեկ վայրկյանից պակաս ժամանակում միլիարդ տողեր հանել, եթե ձեր համակարգում շատ միջուկներ ունեք: Ժամանակային շարքերի կետերի սկանավորում VictoriaMetrics-ում – 50 միավոր վայրկյանում մեկ միջուկում: Եվ այս կատարումը չափվում է գոյություն ունեցող միջուկներին: Այսինքն, եթե ունես, օրինակ, 000 միջուկ, վայրկյանում կսկանավորես միլիարդ միավոր։ Եվ VictoriaMetrics-ի և ClickHouse-ի այս հատկությունը նվազեցնում է կրճատման անհրաժեշտությունը:

Մեկ այլ առանձնահատկությունն այն է, որ VictoriaMetrics-ը արդյունավետորեն սեղմում է այս տվյալները: Արտադրության մեջ միջինում սեղմումը կազմում է 0,4-ից մինչև 0,8 բայթ մեկ կետում: Յուրաքանչյուր կետ իրենից ներկայացնում է ժամանակի դրոշմակնիք + արժեք: Եվ այն սեղմվում է միջինում մեկ բայթից պակաս:

Սերգեյ. Ես հարց ունեմ. Ո՞րն է ձայնագրման նվազագույն ժամանակի քվանտը:

Մեկ միլիվայրկյան. Վերջերս մենք զրույց ունեցանք ժամանակային շարքերի տվյալների բազայի այլ մշակողների հետ: Նրանց նվազագույն ժամանակային հատվածը մեկ վայրկյան է: Իսկ Գրաֆիտում, օրինակ, դա նույնպես մեկ վայրկյան է: OpenTSDB-ում այն ​​նույնպես մեկ վայրկյան է։ InfluxDB-ն ունի նանովայրկյանական ճշգրտություն: VictoriaMetrics-ում դա մեկ միլիվայրկյան է, քանի որ Պրոմեթևսում մեկ միլիվայրկյան է։ Եվ VictoriaMetrics-ը ի սկզբանե մշակվել է որպես Պրոմեթևսի հեռավոր պահեստ: Սակայն այժմ այն ​​կարող է պահպանել տվյալներ այլ համակարգերից:

Անձը, ում հետ ես խոսեցի, ասում է, որ նրանք ունեն վայրկյանից վայրկյան ճշգրտություն, դա նրանց համար բավական է, քանի որ դա կախված է տվյալների տեսակից, որոնք պահվում են ժամանակային շարքերի տվյալների բազայում: Եթե ​​դա DevOps-ի տվյալներն են կամ ենթակառուցվածքից ստացված տվյալներ, որտեղ դրանք հավաքում եք րոպեում 30 վայրկյան ընդմիջումներով, ապա վայրկյանների ճշգրտությունը բավական է, ձեզ պակաս ոչինչ պետք չէ: Եվ եթե դուք հավաքում եք այս տվյալները բարձր հաճախականությամբ առևտրային համակարգերից, ապա ձեզ անհրաժեշտ է նանովայրկյան ճշգրտություն:

VictoriaMetrics-ում միլիվայրկյան ճշգրտությունը նույնպես հարմար է DevOps գործի համար և կարող է հարմար լինել այն դեպքերի մեծ մասի համար, որոնք ես նշեցի զեկույցի սկզբում: Միակ բանը, որի համար այն չի կարող հարմար լինել, բարձր հաճախականությամբ առևտրային համակարգերն են:

Շնորհակալություն! Եվ ևս մեկ հարց. Ի՞նչ է համատեղելիությունը PromQL-ում:

Ամբողջական հետընթաց համատեղելիություն: VictoriaMetrics-ը լիովին աջակցում է PromQL-ին: Բացի այդ, այն ավելացնում է լրացուցիչ առաջադեմ գործառույթներ PromQL-ում, որը կոչվում է MetricsQL. YouTube-ում խոսակցություն կա այս ընդլայնված ֆունկցիոնալության մասին: Ես ելույթ եմ ունեցել Սանկտ Պետերբուրգում գարնանը կայացած Մոնիտորինգի հանդիպման ժամանակ:

Telegram ալիք VictoriaMetrics.

Հարցմանը կարող են մասնակցել միայն գրանցված օգտվողները։ Մուտք գործել, խնդրում եմ:

Ի՞նչն է խանգարում ձեզ անցնել VictoriaMetrics-ին՝ որպես Պրոմեթևսի երկարաժամկետ պահեստ: (Գրեք մեկնաբանություններում, ես կավելացնեմ հարցման մեջ))

  • 71,4%Ես չեմ օգտագործում Prometheus5-ը

  • 28,6%Ես չգիտեի VictoriaMetrics2-ի մասին

Քվեարկել է 7 օգտատեր։ 12 օգտատեր ձեռնպահ է մնացել։

Source: www.habr.com

Добавить комментарий