{"id":80733,"date":"2020-05-08T13:42:31","date_gmt":"2020-05-08T11:42:31","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin"},"modified":"2020-05-08T13:42:31","modified_gmt":"2020-05-08T11:42:31","slug":"go-optimizations-in-victoriametrics-aleksandr-valyalkin","status":"publish","type":"post","link":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","title":{"rendered":"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Jeg vil gerne pr\u00e6sentere oversigten over Alexander Valjalkins rapport fra slutningen af 2019 \"Go optimeringer i VictoriaMetrics\"<\/strong><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/victoriametrics.com\/\">VictoriaMetrics<\/a><\/noindex> \u2014 en hurtig og skalerbar DBMS til opbevaring og behandling af data i form af tidsserier (en optagelse best\u00e5r af tid og et s\u00e6t v\u00e6rdier svarende til denne tid, f.eks. opn\u00e5et gennem periodisk polling af sensorstatus eller indsamling af metrics).<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/dd13ec10594aeb138be29ce439cc476a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Her er et link til videoen af denne rapport \u2014 <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/MZ5P21j_HLE\">https:\/\/youtu.be\/MZ5P21j_HLE<\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/docs.google.com\/presentation\/d\/1k7OjHvxTHA7669MFwsNTCx8hII-a8lNvpmQetLxmrEU\/edit?usp=sharing\">Slides<\/a><\/noindex><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/0073390d6dbcc6ab3e5305907ac6a229.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad mig fort\u00e6lle lidt om mig selv. Jeg er Alexander Valyalkin. Her er <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/valyala\">min GitHub-konto<\/a><\/noindex>. Jeg har en passion for Go og performanceoptimering. Jeg har skrevet mange forskellige nyttige og mindre nyttige biblioteker. De starter enten med <code>fast<\/code>, eller med <code>quick<\/code> pr\u00e6fikset. <\/p>\n<p><\/p>\n<p>I \u00f8jeblikket arbejder jeg p\u00e5 VictoriaMetrics. Hvad er det, og hvad laver jeg der? Dette vil jeg forklare i denne pr\u00e6sentation. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c9194bc3fee1f615d838979bec12f7d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Planen for rapporten er som f\u00f8lger:<\/p>\n<p><\/p>\n<ul>\n<li>F\u00f8rst vil jeg fort\u00e6lle jer, hvad VictoriaMetrics er. <\/li>\n<li>Derefter vil jeg forklare, hvad tidsserier er. <\/li>\n<li>S\u00e5 vil jeg fort\u00e6lle, hvordan en tidsseriedatabase fungerer.<\/li>\n<li>Dern\u00e6st vil jeg tale om databasedesignen: hvad den best\u00e5r af.<\/li>\n<li>Og s\u00e5 g\u00e5r vi videre til optimeringerne i VictoriaMetrics. Dette inkluderer optimering af den inverterede indeks og bitset-implementering p\u00e5 Go.<\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/3e0244b6b6fe952f660e4a094778921a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ved nogen i publikum, hvad VictoriaMetrics er? Wow, mange mennesker ved allerede det. Det er en god nyhed. For dem der ikke ved det \u2013 det er en database til tidsserier. Den er baseret p\u00e5 ClickHouse-arkitekturen og visse detaljer i implementeringen af ClickHouse. For eksempel: MergeTree, parallel beregning p\u00e5 alle tilg\u00e6ngelige kerner af processoren og optimering af ydeevne med fokus p\u00e5 datablokke, som gemmes i processorens cache. <\/p>\n<p><\/p>\n<p>VictoriaMetrics tilbyder den bedste datakomprimering sammenlignet med andre databaser designet til tidsserier. <\/p>\n<p><\/p>\n<p>Den skalerer vertikalt \u2014 dvs. du kan tilf\u00f8je flere processorer, mere RAM p\u00e5 \u00e9n maskine. VictoriaMetrics vil effektivt udnytte disse tilg\u00e6ngelige ressourcer og forbedre den line\u00e6re ydeevne.<\/p>\n<p><\/p>\n<p>Desuden skalerer VictoriaMetrics horisontalt \u2014 dvs. du kan tilf\u00f8je flere noder til VictoriaMetrics-klyngen, og dens ydeevne vil vokse n\u00e6sten line\u00e6rt.<\/p>\n<p><\/p>\n<p>Som du m\u00e5ske har g\u00e6ttet, er VictoriaMetrics en hurtig database, fordi jeg ikke kan skrive om andre. Og den er skrevet i Go, s\u00e5 det er derfor, jeg taler om den p\u00e5 dette meetup.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/0121c9baead722eb1fe22fb6f900d4ad.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvem ved, hvad en tidsserie er? Mange mennesker ved det ogs\u00e5. En tidsserie er en r\u00e6kke par <code>(timestamp, v\u00e6rdi)<\/code>, hvor disse par er sorteret efter tid. V\u00e6rdien er et flydende tal \u2013 float64.<\/p>\n<p><\/p>\n<p>Hver tidsserie er unikt identificeret ved en n\u00f8gle. Hvad best\u00e5r denne n\u00f8gle af? Den best\u00e5r af et ikke-tomt s\u00e6t n\u00f8gle-v\u00e6rdi-par. <\/p>\n<p><\/p>\n<p>Her er et eksempel p\u00e5 en tidsserie. N\u00f8glen til denne serie er en liste af par: <code>__name__=\"cpu_usage\"<\/code> \u2013 dette er navnet p\u00e5 metrikken, <code>instance=\"my-server\"<\/code> \u2013 dette er computeren, hvor denne metrik er indsamlet, <code>datacenter=\"us-east\"<\/code> \u2013 dette er datacenteret, hvor denne computer st\u00e5r.<\/p>\n<p><\/p>\n<p>Vi har f\u00e5et navnet p\u00e5 tidsserien, som best\u00e5r af tre n\u00f8gle-v\u00e6rdi-par. Denne n\u00f8gle svarer til listen af par <code>(timestamp, v\u00e6rdi)<\/code>. <code>t1, t3, t3, ..., tN<\/code> \u2013 dette er timestamps, <code>10, 20, 12, ..., 15<\/code> \u2013 de tilsvarende v\u00e6rdier. Dette er cpu-brug p\u00e5 det nuv\u00e6rende tidspunkt for den p\u00e5g\u00e6ldende serie.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/76cab9db0263318d355ac607ceb7e0f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvor kan tidsserier anvendes? Er der nogen id\u00e9er? <\/p>\n<p><\/p>\n<ul>\n<li>I DevOps kan man m\u00e5le CPU-belastning, RAM, netv\u00e6rk, rps, antal fejl osv. <\/li>\n<li>IoT \u2013 vi kan m\u00e5le temperatur, tryk, geografiske koordinater og mere.<\/li>\n<li>Ogs\u00e5 i finans \u2013 vi kan overv\u00e5ge priser p\u00e5 aktier og valutaer. <\/li>\n<li>Derudover kan tidsserier bruges til overv\u00e5gning af produktionsprocesser p\u00e5 fabrikker. Vi har brugere, der bruger VictoriaMetrics til at overv\u00e5ge vindm\u00f8ller, til robotter.<\/li>\n<li>Tidsserier er ogs\u00e5 nyttige til at indsamle oplysninger fra sensorer p\u00e5 forskellige enheder. For eksempel, til motoren; til m\u00e5ling af d\u00e6ktryk; til m\u00e5ling af hastighed, afstand; til m\u00e5ling af br\u00e6ndstofforbrug osv.<\/li>\n<li>Tidsserier kan ogs\u00e5 anvendes til overv\u00e5gning af fly. Hver flyvning har en sort boks, der indsamler tidsserier om forskellige parametre for flyets sundhed. Tidsserier anvendes ogs\u00e5 i luftfartsindustrien. <\/li>\n<li>Sundhedspleje \u2013 det er blodtryk, puls osv.<\/li>\n<\/ul>\n<p><\/p>\n<p>M\u00e5ske er der andre anvendelser, som jeg har glemt, men jeg h\u00e5ber, at I forst\u00e5r, at tidsserier aktivt anvendes i den moderne verden. Og omfanget af deres anvendelse vokser hvert \u00e5r.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/f1da29d372163751268b6a8f86836d04.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvad er behovet for en database til tidsserier? Hvorfor kan man ikke bruge en almindelig relationsdatabase til at opbevare tidsserier?<\/p>\n<p><\/p>\n<p>Fordi tidsserier normalt har et stort volumen af information, der er sv\u00e6rt at gemme og behandle i almindelige databaser. Derfor er der opst\u00e5et specialiserede databaser til tidsserier. Disse databaser gemmer effektivt datapunkter <code>(timestamp, v\u00e6rdi)<\/code> med en given n\u00f8gle. De tilbyder et API til at l\u00e6se de gemte data baseret p\u00e5 n\u00f8glen, \u00e9n n\u00f8gle-v\u00e6rdi-par ad gangen, eller flere s\u00e5danne par, eller ved hj\u00e6lp af regexp. For eksempel, hvis du \u00f8nsker at finde CPU-belastningen for alle dine tjenester i datacenteret i Amerika, skal du bruge en s\u00e5dan pseudo-foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<p>Normalt pr\u00e6senterer databaser til tidsserier specialiserede foresp\u00f8rgselsprog, fordi SQL ikke er s\u00e6rlig godt tilpasset til tidsserier. Selvom der findes databaser, der underst\u00f8tter SQL, er det ikke s\u00e6rlig godt tilpasset. Mere passende foresp\u00f8rgselsprog er <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@valyala\/promql-tutorial-for-beginners-9ab455142085\">PromQL<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.influxdata.com\/influxdb\/v1.8\/query_language\/spec\/\">InfluxQL<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.influxdata.com\/products\/flux\/\">Flux<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/code.kx.com\/q\/\">Q<\/a><\/noindex>. Jeg h\u00e5ber, at nogen har h\u00f8rt om mindst \u00e9t af disse sprog. Om PromQL har mange sikkert h\u00f8rt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/59e5b6d82a2f7861077bc5fe34519ee4.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her er, hvordan arkitekturen af en moderne database til tidsserier ser ud, med VictoriaMetrics som eksempel.<\/p>\n<p><\/p>\n<p>Den best\u00e5r af to dele. Det er et lager til den inverterede indeks og et lager til tidsseriev\u00e6rdierne. Disse lagre er adskilt. <\/p>\n<p><\/p>\n<p>N\u00e5r der kommer en ny post i databasen, kontakter vi f\u00f8rst den inverterede indeks for at finde identifikatoren for tidsserien baseret p\u00e5 det angivne s\u00e6t <code>label=value<\/code> for denne m\u00e5ling. Vi finder denne identifikator og gemmer v\u00e6rdien i datalageret.<\/p>\n<p><\/p>\n<p>N\u00e5r der kommer en foresp\u00f8rgsel om at hente data fra TSDB, kigger vi f\u00f8rst i den inverterede indeks. Vi henter alle <code>timeseries_ids<\/code> poster, der svarer til det angivne s\u00e6t. <code>label=value<\/code>Og derefter henter vi alle n\u00f8dvendige data fra datalageret, som er indekseret efter <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/eb9b36fa3c6de2188b97b56ad3839b2c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os overveje et eksempel p\u00e5, hvordan en database til tidsserier behandler en indg\u00e5ende select-foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<ul>\n<li>F\u00f8rst henter den alle <code>timeseries_ids<\/code> fra den inverterede indeks, der indeholder de angivne par <code>label=value<\/code>, eller som opfylder det angivne regul\u00e6re udtryk.<\/li>\n<li>S\u00e5 henter den alle data points fra datalageret for det angivne tidsinterval for de fundne <code>timeseries_ids<\/code>.<\/li>\n<li>Derefter udf\u00f8rer databasen nogle beregninger p\u00e5 disse data points i henhold til brugerens foresp\u00f8rgsel. Og derefter returnerer den svaret.<\/li>\n<\/ul>\n<p><\/p>\n<p>I denne pr\u00e6sentation vil jeg fort\u00e6lle dig om den f\u00f8rste del. Det er s\u00f8gning. <code>timeseries_ids<\/code> efter det inverterede indeks. Du kan senere kigge p\u00e5 del to og del tre. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">kildefilerne til VictoriaMetrics<\/a><\/noindex>, eller vent, mens jeg forbereder andre pr\u00e6sentationer \ud83d\ude42<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/3a7dab707dd1defb9bc674a342052a03.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os begynde med det inverterede indeks. Mange vil m\u00e5ske synes, at det er enkelt. Hvem ved, hvad et inverteret indeks er, og hvordan det fungerer? \u00c5h, allerede ikke s\u00e5 mange mennesker. Lad os fors\u00f8ge at forst\u00e5, hvad det g\u00e5r ud p\u00e5. <\/p>\n<p><\/p>\n<p>Det er faktisk ret simpelt. Dette er bare et ordbog, der kortl\u00e6gger n\u00f8gle til v\u00e6rdi. Hvad er en n\u00f8gle? Dette par <code>label=value<\/code>, hvor <code>label<\/code> og <code>value<\/code> \u2013 er strenge. Og v\u00e6rdierne er et s\u00e6t <code>timeseries_ids<\/code>, som indeholder det angivne par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Det inverterede indeks g\u00f8r det muligt hurtigt at finde alle <code>timeseries_ids<\/code>, der har angivne <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Det g\u00f8r det ogs\u00e5 muligt hurtigt at finde <code>timeseries_ids<\/code> tidsserier for flere par <code>label=value<\/code>, eller for par <code>label=regexp<\/code>. Hvordan sker det? Ved at finde sk\u00e6ringspunktet for m\u00e6ngden <code>timeseries_ids<\/code> for hvert par <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/837a15a078e8c9422c721f3f072c0c09.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os se p\u00e5 forskellige implementeringer af det inverterede indeks. Vi starter med den mest enkle naive implementering. Den ser s\u00e5dan ud. <\/p>\n<p><\/p>\n<p>Funktion <code>getMetricIDs<\/code> f\u00e5r en liste af strenge. Hver streng indeholder <code>label=value<\/code>. Denne funktion returnerer en liste <code>metricIDs<\/code>.<\/p>\n<p><\/p>\n<p>Hvordan fungerer det? Her har vi en global variabel kaldet <code>invertedIndex<\/code>. Dette er et almindeligt ordbog (<code>kortl\u00e6gning<\/code>), der kortl\u00e6gger en streng til en slice af ints. Strengen indeholder <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Implementeringen af funktionen: henter <code>metricIDs<\/code> for den f\u00f8rste <code>label=value<\/code>, derefter gennemg\u00e5r vi alle de andre <code>label=value<\/code>, henter <code>metricIDs<\/code> for dem. Og kalder funktionen <code>intersectInts<\/code>, som vil blive beskrevet senere. Og denne funktion returnerer sk\u00e6ringspunktet for disse lister.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/709beca79884a9693098781974c26f4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Som du kan se, er implementeringen af det inverterede indeks ikke s\u00e6rlig kompliceret. Men det er en naiv implementering. Hvad er dens ulemper? Den st\u00f8rste ulempe ved den naive implementering er, at et s\u00e5dant inverteret indeks opbevares i RAM. Efter genstart af applikationen mister vi dette indeks. Der er ingen gemning af dette indeks p\u00e5 disk. Til en database vil et s\u00e5dant inverteret indeks n\u00e6ppe v\u00e6re passende.<\/p>\n<p><\/p>\n<p>Den anden ulempe er ogs\u00e5 relateret til hukommelse. Det inverterede indeks skal v\u00e6re i RAM. Hvis det overstiger st\u00f8rrelsen af RAM, f\u00e5r vi \u00e5benbart \u2013 out of memory error. Og programmet fungerer ikke.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/495394168ac03aa8cbcf56ccad1cb2b8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette problem kan l\u00f8ses med hj\u00e6lp fra f\u00e6rdige l\u00f8sninger s\u00e5som <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/google\/leveldb\">LevelDB<\/a><\/noindex>, eller <noindex><a rel=\"nofollow\" href=\"https:\/\/rocksdb.org\/\">RocksDB<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Kort sagt, vi har brug for en database, der hurtigt kan udf\u00f8re tre operationer. <\/p>\n<p><\/p>\n<ul>\n<li>Den f\u00f8rste operation er at skrive <code>n\u00f8gle-v\u00e6rdi<\/code> til denne database. Det g\u00f8r den meget hurtigt, hvor <code>n\u00f8gle-v\u00e6rdi<\/code> \u2013 er vilk\u00e5rlige strenge. <\/li>\n<li>Den anden operation er hurtig s\u00f8gning efter v\u00e6rdien baseret p\u00e5 en given n\u00f8gle.<\/li>\n<li>Og den tredje operation er hurtig s\u00f8gning efter alle v\u00e6rdier baseret p\u00e5 et givet pr\u00e6fiks. <\/li>\n<\/ul>\n<p><\/p>\n<p>LevelDB og RocksDB \u2013 disse databaser er udviklet af Google og Facebook. F\u00f8rst kom LevelDB. S\u00e5 tog folkene fra Facebook LevelDB og begyndte at forbedre den, hvilket resulterede i RocksDB. I dag k\u00f8rer n\u00e6sten alle interne databaser hos Facebook p\u00e5 RocksDB, inklusive at de har overf\u00f8rt MySQL til RocksDB. De kaldte det <noindex><a rel=\"nofollow\" href=\"http:\/\/myrocks.io\/\">MyRocks<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Et inverteret indeks kan implementeres ved hj\u00e6lp af LevelDB. Hvordan g\u00f8r vi det? Vi gemmer som n\u00f8gle <code>label=value<\/code>. Og som v\u00e6rdi \u2013 tidsserie-identifikatoren, hvor parret optr\u00e6der <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p>Hvis vi har mange tidsserier med dette par <code>label=value<\/code>, s\u00e5 vil der v\u00e6re mange r\u00e6kker i denne database med den samme n\u00f8gle og forskellige <code>timeseries_ids<\/code>. For at f\u00e5 listen over alle <code>timeseries_ids<\/code>, der starter med det angivne <code>label=prefix<\/code>, foretager vi en range scan, som denne database er optimeret til. Dvs. vi v\u00e6lger alle r\u00e6kker, der starter med <code>label=prefix<\/code> og f\u00e5r de n\u00f8dvendige <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/a40877ecb758ac3bc1979bcd568d7e83.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her er en omtrentlig implementering af, hvordan det ville se ud i Go. Vi har et inverteret indeks. Det er LevelDB.<\/p>\n<p><\/p>\n<p>Funktionen er den samme som for den naive implementering. Den gentager n\u00e6sten linje for linje den naive implementering. Den eneste forskel er, at vi i stedet for at henvise til <code>kortl\u00e6gning<\/code> henvender os til det inverterede indeks. Vi henter alle v\u00e6rdierne for den f\u00f8rste <code>label=value<\/code>. S\u00e5 g\u00e5r vi igennem alle de resterende par <code>label=value<\/code> og henter de relevante s\u00e6t af metricIDs for dem. Derefter finder vi sk\u00e6ringspunktet. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/de11b15286816ada04b22727ff78e43d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det virker alt sammen godt, men der er ulemper ved denne l\u00f8sning. VictoriaMetrics implementerede oprindeligt et inverteret indeks baseret p\u00e5 LevelDB. Men i sidste ende m\u00e5tte de opgive det.<\/p>\n<p><\/p>\n<p>Hvorfor? Fordi LevelDB er langsommere end den naive implementering. I den naive implementering henter vi med det samme hele slice baseret p\u00e5 den givne n\u00f8gle <code>metricIDs<\/code>. Denne operation er meget hurtig \u2013 hele slice er klar til brug.<\/p>\n<p><\/p>\n<p>I LevelDB skal man derimod ved hvert kald af funktionen <code>GetValues<\/code> gennemg\u00e5 alle r\u00e6kker, der starter med <code>label=value<\/code>. Og for hver r\u00e6kke hente v\u00e6rdien <code>timeseries_ids<\/code>. Fra disse <code>timeseries_ids<\/code> samle et slice af disse <code>timeseries_ids<\/code>. Det er \u00e5benlyst, at dette er meget langsommere end blot at f\u00e5 adgang til en almindelig map ved hj\u00e6lp af n\u00f8glen.<\/p>\n<p><\/p>\n<p>Den anden ulempe er, at LevelDB er skrevet i C. Adgangen til C-funktioner fra Go er ikke s\u00e6rlig hurtig. Det tager hundrede nanosekunder. Det er ikke hurtigt, fordi det sammenlignet med et almindeligt funktionsopkald, der er skrevet i Go, som tager 1-5 nanosekunder, betyder, at der er en forskel i ydeevne p\u00e5 mange gange. For VictoriaMetrics var dette en fatal ulempe \ud83d\ude42<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/47cace825807b7b062064c2e790dc9d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Derfor har jeg skrevet min egen implementering af et inverteret indeks. Jeg kaldte det <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/mergeset\">mergeset<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Mergeset er baseret p\u00e5 datalayoutet MergeTree. Denne datastruktur er l\u00e5nt fra ClickHouse. Det er klart, at mergeset skal optimeres til hurtig s\u00f8gning <code>timeseries_ids<\/code> efter en given n\u00f8gle. Mergeset er skrevet helt i Go. Du kan se p\u00e5 <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\">kildekoden til VictoriaMetrics p\u00e5 GitHub<\/a><\/noindex>. Implementeringen af mergeset ligger i mappen <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/mergeset\">\/lib\/mergeset<\/a><\/noindex>. Du kan pr\u00f8ve at finde ud af, hvad der sker der.<\/p>\n<p><\/p>\n<p>API'et for mergeset ligner meget LevelDB og RocksDB. Dvs. det giver mulighed for hurtigt at gemme nye poster der og hurtigt v\u00e6lge poster efter en given pr\u00e6fiks.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/845704ed36f70beb468907d22701af59.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi vil tale om ulemperne ved mergeset senere. Nu vil vi tale om, hvilke problemer der opstod med VictoriaMetrics i produktion ved implementeringen af det inverterede indeks.<\/p>\n<p><\/p>\n<p>Hvorfor opstod de?<\/p>\n<p><\/p>\n<p>Den f\u00f8rste \u00e5rsag er den h\u00f8je churn rate. P\u00e5 dansk betyder det hyppig skift af tidsserier. Det er, n\u00e5r en tidsserie slutter, og en ny tidsserie starter, eller mange nye tidsserier begynder. Og det sker ofte.<\/p>\n<p><\/p>\n<p>Den anden \u00e5rsag er det store antal tidsserier. I starten, da overv\u00e5gning blev popul\u00e6rt, var antallet af tidsserier lille. For eksempel skal du overv\u00e5ge CPU, hukommelse, netv\u00e6rk og disk for hver computer. 4 tidsserier pr. computer. Hvis du har 100 computere, er der 400 tidsserier. Det er meget lidt. <\/p>\n<p><\/p>\n<p>Over tid opfandt folk, at man kunne m\u00e5le mere detaljeret information. For eksempel at m\u00e5le belastningen p\u00e5 ikke hele CPU'en, men hver enkelt CPU-kerne. Hvis du har 40 CPU-kerner, har du derfor 40 gange flere tidsserier til at m\u00e5le CPU-belastningen. <\/p>\n<p><\/p>\n<p>Men det er ikke alt. Hver processorkerne kan have flere tilstande, s\u00e5som idle, n\u00e5r den ikke bruges. Derudover er der betjening i brugerrum, betjening i kernerum og andre tilstande. Hver af disse tilstande kan ogs\u00e5 m\u00e5les som en separat tidsserie. Dette \u00f8ger antallet af r\u00e6kker med 7-8 gange.<\/p>\n<p><\/p>\n<p>Fra \u00e9n metrik fik vi 40 x 8 = 320 metrikker kun for \u00e9n computer. Ganget med 100 f\u00e5r vi 32.000 i stedet for 400. <\/p>\n<p><\/p>\n<p>Derefter kom Kubernetes. Og det forv\u00e6rrede situationen yderligere, fordi mange forskellige tjenester kan v\u00e6re hostet i Kubernetes. Hver tjeneste i Kubernetes best\u00e5r af mange pods. Alt dette skal overv\u00e5ges. Derudover har vi en konstant implementering af nye versioner af dine tjenester. For hver ny version skal der oprettes nye tidsserier. Resultatet er, at antallet af tidsserier vokser eksponentielt, og vi st\u00e5r over for problemet med det store antal tidsserier, der kaldes high-cardinality. VictoriaMetrics h\u00e5ndterer dette effektivt i forhold til andre tidsserie-databaser. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c11b7ce6d3294ae420243f72636af4b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os se n\u00e6rmere p\u00e5 high churn rate. Hvad for\u00e5rsager high churn rate i produktion? Fordi nogle v\u00e6rdier af labels og tags konstant \u00e6ndres.<\/p>\n<p><\/p>\n<p>For eksempel, lad os tage Kubernetes, som har begrebet <code>deployment<\/code>, dvs. n\u00e5r der lanceres en ny version af din applikation. Kubernetes-udviklerne har af en eller anden grund besluttet at tilf\u00f8je deployment-ID'en til label.<\/p>\n<p><\/p>\n<p>Hvad f\u00f8rte det til? At hver nye deployment medf\u00f8rer, at alle gamle tidsserier afbrydes, og i stedet begynder nye tidsserier med den nye label-v\u00e6rdi. <code>deployment_id<\/code>. Der kan v\u00e6re hundrede tusinde og endda millioner af s\u00e5danne r\u00e6kker.<\/p>\n<p><\/p>\n<p>En vigtig egenskab ved det hele er, at det samlede antal tidsserier vokser, men antallet af tidsserier, der i \u00f8jeblikket er aktive og modtager data, forbliver konstant. Denne tilstand kaldes high churn rate.<\/p>\n<p><\/p>\n<p>Det prim\u00e6re problem med high churn rate er at sikre en konstant s\u00f8gehastighed for alle tidsserier baseret p\u00e5 et givet s\u00e6t labels over et bestemt tidsinterval. Dette interval er normalt det sidste time eller den sidste dag. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/ac18482b87cc37624d163b30c68cf7be.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan l\u00f8ser vi dette problem? Her er det f\u00f8rste forslag. Det er at opdele den inverterede indeks i uafh\u00e6ngige dele baseret p\u00e5 tid. Det vil sige, n\u00e5r en periode er g\u00e5et, stopper vi med at arbejde med den nuv\u00e6rende inverterede indeks og opretter en ny inverteret indeks. N\u00e5r endnu en periode er g\u00e5et, opretter vi endnu en og endnu en. <\/p>\n<p><\/p>\n<p>Og n\u00e5r vi henter fra disse inverterede indekser, finder vi et s\u00e6t inverterede indekser, der falder inden for det angivne interval. Og derfra v\u00e6lger vi id'erne for de tidsserier. <\/p>\n<p><\/p>\n<p>Dette sparer ressourcer, fordi vi ikke beh\u00f8ver at gennemg\u00e5 dele, der ikke falder inden for det angivne interval. Det vil sige, at hvis vi normalt v\u00e6lger data for den seneste time, springer vi foresp\u00f8rgsler over for de tidligere tidsintervaller. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1afa3a88caa7423941ae3494b9cec706.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Der er endnu en l\u00f8sning p\u00e5 dette problem. Det er at gemme en separat liste over id'er for tidsserier, der optr\u00e5dte for hver dag.<\/p>\n<p><\/p>\n<p>Fordelen ved denne l\u00f8sning i forhold til den tidligere l\u00f8sning er, at vi ikke duplikerer informationen om tidsserier, der ikke forsvinder over tid. De er konstant til stede og \u00e6ndrer sig ikke. <\/p>\n<p><\/p>\n<p>Ulempen er, at denne l\u00f8sning er sv\u00e6rere at implementere og sv\u00e6rere at fejlfinde. Og VictoriaMetrics har valgt denne l\u00f8sning. Det skete historisk. Denne l\u00f8sning pr\u00e6sterer ogs\u00e5 godt i forhold til den tidligere, fordi den ikke blev implementeret p\u00e5 grund af behovet for at duplikere data i hver partition for tidsserier, der ikke \u00e6ndres, det vil sige de, der ikke forsvinder over tid. VictoriaMetrics var f\u00f8rst og fremmest optimeret til diskforbrug, og den tidligere implementering forv\u00e6rrede diskforbruget. Men denne implementering passer bedre til at minimere diskforbruget, s\u00e5 den blev valgt. <\/p>\n<p><\/p>\n<p>Vi m\u00e5tte k\u00e6mpe med dette. Kampen bestod i, at man i denne implementering stadig skal v\u00e6lge et v\u00e6sentligt st\u00f8rre antal <code>timeseries_ids<\/code> for data end n\u00e5r den inverterede indeks er opdelt efter tid.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/5b10e61aaa803428ed3bfe31815f09d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan l\u00f8ste vi dette problem? Vi l\u00f8ste det p\u00e5 en original m\u00e5de \u2013 ved at gemme flere identifikatorer for tidsserier i hver post af den inverterede indeks i stedet for \u00e9n identifikator. Det vil sige, vi har en n\u00f8gle <code>label=value<\/code>, som findes i hver tidsr\u00e6kke. Og nu gemmer vi flere <code>timeseries_ids<\/code> i \u00e9n optagelse.<\/p>\n<p><\/p>\n<p>Her er et eksempel. Tidligere havde vi N optagelser, men nu har vi \u00e9n optagelse, hvis pr\u00e6fiks er det samme som for alle de andre. Den tidligere optagelse indeholdt alle ID\u2019erne fra tidsr\u00e6kkerne. <\/p>\n<p><\/p>\n<p>Dette har \u00f8get hastigheden for scanning af en s\u00e5dan inverteret indeks op til 10 gange. Og det har reduceret hukommelsesforbruget til cachen, fordi vi nu gemmer strengen <code>label=value<\/code> kun \u00e9n gang i cachen sammen med N gange. Og denne streng kan v\u00e6re stor, hvis du har lange strenge gemt i tags og labels, som Kubernetes elsker at stoppe der.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/ae4f38a440203bad2d03cf2abd1faafe.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>En anden metode til at accelerere s\u00f8gningen i det inverterede indeks er sharding. Ved at oprette flere inverterede indekser i stedet for \u00e9n og shard dataene mellem dem baseret p\u00e5 en n\u00f8gle. Dette er et s\u00e6t <code>n\u00f8gle=v\u00e6rdi<\/code> par. Det vil sige, at vi f\u00e5r flere uafh\u00e6ngige inverterede indekser, som vi kan foresp\u00f8rge parallelt p\u00e5 flere processorer. Tidligere implementeringer tillod kun at fungere i en-processor-tilstand, det vil sige, at dataene kun kunne scannes p\u00e5 \u00e9n kerne. Denne l\u00f8sning g\u00f8r det muligt at scanne data p\u00e5 flere kerner p\u00e5 \u00e9n gang, som ClickHouse gerne g\u00f8r. Det planl\u00e6gger vi at implementere.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/5ced6446efbf8ded8d7fb91694a999b0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og nu lad os vende tilbage til sagen \u2013 til intersections-funktionen <code>timeseries_ids<\/code>. Lad os overveje, hvad der kan v\u00e6re af implementeringer. Denne funktion g\u00f8r det muligt at finde <code>timeseries_ids<\/code> for et givet s\u00e6t <code>label=value<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/073a155018a91120c6996c324772f9af.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Den f\u00f8rste mulighed er en naiv implementering. To indlejrede l\u00f8kker. Her f\u00e5r vi som input til funktionen <code>intersectInts<\/code> to slices \u2014 <code>en<\/code> og <code>b<\/code>. Som output skal den returnere os intersection af disse slices.<\/p>\n<p><\/p>\n<p>Den naive implementering ser s\u00e5dan ud. Vi g\u00e5r igennem alle v\u00e6rdierne fra slice <code>en<\/code>, inden i denne l\u00f8kke bruger vi alle v\u00e6rdierne fra slice <code>b<\/code>. Og vi sammenligner dem. Hvis de matcher, har vi fundet intersection. Og vi gemmer det i <code>resultat<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/b89dcbb4f6d73377f9cf4f50169d6dd7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilke ulemper er der? Den kvadratiske kompleksitet \u2014 det er dens hovedulempen. For eksempel, hvis du har st\u00f8rrelserne p\u00e5 slices <code>en<\/code> og <code>b<\/code> p\u00e5 en million, s\u00e5 vil denne funktion aldrig returnere et svar. Fordi den skal lave en trillion iterationer, hvilket er meget selv for moderne computere.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/bad26b0092a2fd7fc813bcb79a9138ce.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Den anden implementering er baseret p\u00e5 map. Vi opretter en map. S\u00e6tter alle v\u00e6rdierne fra slice <code>en<\/code>. Derefter l\u00f8ber vi gennem slice <code>b<\/code>. Og vi tjekker \u2013 er der denne v\u00e6rdi fra slice <code>b<\/code> i map. Hvis den findes, tilf\u00f8jer vi den til resultatet. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1e610acf641a9cfe4c80aac1fe26044c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvilke fordele er der? Fordelen er, at der kun er line\u00e6r kompleksitet. Det vil sige, at funktionen udf\u00f8res meget hurtigere for store st\u00f8rrelser af slices. For en slice med en million elementer vil denne funktion udf\u00f8res p\u00e5 2 millioner iterationer, i mods\u00e6tning til en billion iterationer som i den forrige funktion.<\/p>\n<p><\/p>\n<p>En ulempe er, at denne funktion kr\u00e6ver mere hukommelse for at oprette denne map.<\/p>\n<p><\/p>\n<p>Den anden ulempe er den store overhead ved hashing. Denne ulempe er ikke s\u00e5 \u00e5benlys. Og for os var den heller ikke s\u00e6rlig \u00e5benlys, derfor blev intersection-implementeringen i VictoriaMetrics oprindeligt lavet via map. Men profilering viste, at den st\u00f8rste del af CPU-tiden gik til at skrive i map og kontrollere tilstedev\u00e6relsen af v\u00e6rdier i denne map.<\/p>\n<p><\/p>\n<p>Hvorfor tager disse steder CPU-tid? Fordi Go i disse linjer udf\u00f8rer en hash-operation. Det vil sige, at den beregner hash for n\u00f8glen, for derefter at f\u00e5 adgang til den angivne indeks i HashMap. Operationen med at beregne hash udf\u00f8res p\u00e5 tiendedel af nanosekunder. Det er langsomt for VictoriaMetrics.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/969f10d875d88998e958894ca28b1181.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jeg besluttede at implementere en bitset, der er specielt optimeret til dette tilf\u00e6lde. S\u00e5dan ser intersection af to slices nu ud. Her opretter vi en bitset. Vi tilf\u00f8jer elementer fra den f\u00f8rste slice. Derefter kontrollerer vi om disse elementer findes i den anden slice. Og vi tilf\u00f8jer dem til resultatet. Det vil sige, at det n\u00e6sten ikke adskiller sig fra det forrige eksempel. Det eneste, vi har \u00e6ndret, er at erstatte adgangen til map med brugerdefinerede funktioner. <code>add<\/code> og <code>has<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/b4ec0753d30d9684868a031f605632c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ved f\u00f8rste \u00f8jekast ser det ud til, at dette skulle v\u00e6re langsommere, hvis der tidligere blev brugt en standard map, og nu kaldes der ogs\u00e5 nogle funktioner, men profileringen viser, at denne metode fungerer ti gange hurtigere end standard map i forbindelse med VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Derudover bruger den meget mindre hukommelse sammenlignet med implementeringen p\u00e5 map. Fordi vi opbevarer bits i stedet for otte-bytes v\u00e6rdier.<\/p>\n<p><\/p>\n<p>Ulempen ved denne implementering er, at den ikke er s\u00e5 \u00e5benlys, ikke triviel. <\/p>\n<p><\/p>\n<p>En anden ulempe, som mange m\u00e5ske ikke bem\u00e6rker, er, at denne implementering kan fungere d\u00e5rligt i visse tilf\u00e6lde. Det vil sige, den er optimeret til et specifikt tilf\u00e6lde, til netop dette tilf\u00e6lde med overlapning af ids for tidsserier i VictoriaMetrics. Det betyder ikke, at den vil v\u00e6re egnet for alle situationer. Hvis den bruges forkert, f\u00e5r vi ikke et performance boost, men en out of memory-fejl og nedsat ydeevne. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/94bd174afe43e67b3cf279dc7a1be17c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os se n\u00e6rmere p\u00e5 implementeringen af denne struktur. Hvis du vil se den, findes den i kildekoden til VictoriaMetrics, i mappen <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/tree\/master\/lib\/uint64set\">lib\/uint64set<\/a><\/noindex>. Den er optimeret netop til VictoriaMetrics, hvor <code>timeseries_id<\/code> repr\u00e6senterer en 64-bit v\u00e6rdi, hvor de f\u00f8rste 32 bit er konstant og kun de sidste 32 bit \u00e6ndres.<\/p>\n<p><\/p>\n<p>Denne datastruktur gemmes ikke p\u00e5 disken, den arbejder kun i hukommelsen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/e24ca65f860e2b04037e073f7acae0c1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her er dens API. Det er ikke s\u00e6rlig komplekst. API'et er tilpasset netop det specifikke eksempel p\u00e5 brugen af VictoriaMetrics. Det vil sige, der er ikke un\u00f8dvendige funktioner. Her er funktioner, der tydeligt bruges af VictoriaMetrics.<\/p>\n<p><\/p>\n<p>Der er en funktion <code>add<\/code>, der tilf\u00f8jer nye v\u00e6rdier. Der er en funktion <code>has<\/code>, der tjekker nye v\u00e6rdier. Og der er en funktion <code>del<\/code>, der sletter v\u00e6rdier. Der er en hj\u00e6lpefunktion <code>len<\/code>, der returnerer st\u00f8rrelsen af m\u00e6ngden. Funktionen <code>clone<\/code> kloner m\u00e6ngden. Og funktionen <code>appendto<\/code> omdanner dette s\u00e6t til et slice. <code>timeseries_ids<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/874b04042d13f342d39f8f393e7fb78c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>S\u00e5dan ser implementeringen af denne datastruktur ud. I s\u00e6ttet er der to elementer:<\/p>\n<p><\/p>\n<ul>\n<li>\n<p><code>ItemsCount<\/code> \u2013 det er et hj\u00e6lpefelt for hurtigt at returnere antallet af elementer i s\u00e6ttet. Man kunne have undg\u00e5et dette hj\u00e6lpefelt, men det m\u00e5tte tilf\u00f8jes her, fordi VictoriaMetrics ofte foresp\u00f8rger l\u00e6ngden af bitset i sine algoritmer.<\/p>\n<p>\n<\/li>\n<li>\n<p>Det andet felt er <code>buckets<\/code>. Det er et slice af strukturen <code>bucket32.<\/code>I hver struktur gemmes <code>hi<\/code> feltet. Det er de \u00f8verste 32 bit. Og to slices \u2014 <code>b16his<\/code> og <code>buckets<\/code> af <code>bucket16<\/code> strukturer. <\/p>\n<p>\n<\/li>\n<\/ul>\n<p><\/p>\n<p>Her gemmes de \u00f8verste 16 bit fra den anden del af den 64-bit struktur. Og her gemmes bitsets for de nederste 16 bit af hver byte. <\/p>\n<p><\/p>\n<p><code>Bucket64<\/code> best\u00e5r af et array <code>uint64.<\/code>L\u00e6ngden beregnes med hj\u00e6lp af disse konstanter. I \u00e9n <code>bucket16<\/code> kan der h\u00f8jst gemmes <code>2^16=65536<\/code> bit. Hvis dette deles med 8, bliver det til 8 kilobyte. Hvis det deles igen med 8, bliver det til 1000 <code>uint64.<\/code> v\u00e6rdier. Det vil sige, <code>Bucket16<\/code> er en 8-kilobyte struktur. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/1cca4e6bfafa3408a3c95e0118e26d80.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os se p\u00e5, hvordan en af metoderne til denne struktur tilf\u00f8jer en ny v\u00e6rdi er implementeret. <\/p>\n<p><\/p>\n<p>Det hele begynder med <code>uint64.<\/code> v\u00e6rdier. Vi beregner de \u00f8verste 32 bits, beregner de nederste 32 bits. Vi g\u00e5r igennem alle <code>buckets<\/code>. Vi sammenligner de \u00f8verste 32 bits i hver bucket med den v\u00e6rdi, der tilf\u00f8jes. Og hvis de matcher, kalder vi funktionen <code>add<\/code> i strukturen b32 <code>buckets<\/code>. Og tilf\u00f8jer de nederste 32 bits der. Og hvis dette returnerede <code>true<\/code>, s\u00e5 betyder det, at vi har tilf\u00f8jet en s\u00e5dan v\u00e6rdi der, og vi ikke havde en s\u00e5dan v\u00e6rdi f\u00f8r. Hvis den returnerer <code>false<\/code>, s\u00e5 var en s\u00e5dan v\u00e6rdi allerede der. Derefter \u00f8ger vi antallet af elementer i strukturen. <\/p>\n<p><\/p>\n<p>Hvis vi ikke fandt den n\u00f8dvendige <code>bucket<\/code> med den n\u00f8dvendige hi-v\u00e6rdi, s\u00e5 kalder vi funktionen <code>addAlloc<\/code>, som allokerer en ny <code>bucket<\/code>, ved at tilf\u00f8je den til bucket-strukturen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/c5d1e5de767f47c7c40e01e12b6d0617.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er implementeringen af funktionen <code>b32.add<\/code>. Den ligner den forrige implementering. Vi beregner de \u00f8verste 16 bits, de nederste 16 bits.<\/p>\n<p><\/p>\n<p>Derefter g\u00e5r vi igennem alle de \u00f8verste 16 bits. Finder matches. Og ved match kalder vi metoden add, som vi vil se p\u00e5 n\u00e6ste side for <code>bucket16<\/code>.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/e98c4ef316f3a894fd7019c3c85696f7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og her er det nederste niveau, som skal v\u00e6re maksimeret. Vi beregner for <code>uint64.<\/code> id v\u00e6rdien i slice bit, samt <code>bitmask<\/code>. Dette er en maske for denne 64-bits v\u00e6rdi, som kan bruges til at kontrollere tilstedev\u00e6relsen af denne bit eller s\u00e6tte den. Vi tjekker om denne bit er sat og s\u00e6tter den, og returnerer tilstedev\u00e6relsen. Her er en s\u00e5dan implementering, som tillod at fremskynde operationen af krydsning af ids af tidsserier 10 gange sammenlignet med almindelige maps.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/4dfa5a6142829a3551be22d6c9c3ab92.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I VictoriaMetrics, udover denne optimering, er der mange andre optimeringer. De fleste af disse optimeringer er ikke tilf\u00f8jet bare s\u00e5dan, men efter profilering af koden i produktionen.<\/p>\n<p><\/p>\n<p>Dette er den vigtigste regel for optimering \u2013 ikke tilf\u00f8je optimering, antagende at der vil v\u00e6re et flaskehals, fordi det kan vise sig, at der ikke er nogen flaskehals. Optimering forv\u00e6rre normalt kodekvaliteten. Derfor b\u00f8r man kun optimere efter profilering og helst i produktion, s\u00e5 man arbejder med reelle data. For dem, der er interesserede, kan I se kilden til VictoriaMetrics og studere andre optimeringer, som findes der.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Go-optimeringsmuligheder i VictoriaMetrics. Alexander Valjalkin\" src=\"\/wp-content\/uploads\/2020\/05\/7585c4dc782627bac5b649e6a55e2ffb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><em>Jeg har et sp\u00f8rgsm\u00e5l om bitset. Det ligner meget implementeringen af C++ vector bool, optimeret bitset. Tog I implementeringen derfra?<\/em><\/p>\n<p><\/p>\n<p>Nej, ikke derfra. I implementeringen af dette bitset har jeg v\u00e6ret orienteret om strukturen af disse ids tidserier, som anvendes i VictoriaMetrics. Og deres struktur er s\u00e5dan, at de \u00f8verste 32 bits stort set er konstante. De nederste 32 bits kan \u00e6ndre sig. Jo lavere bit, jo oftere kan den \u00e6ndre sig. Derfor er denne implementering specifikt optimeret til denne datamodel. C++-implementeringen, s\u00e5 vidt jeg ved, er optimeret til den generelle situation. Hvis man laver optimering til den generelle situation, betyder det, at den ikke vil v\u00e6re den mest optimale for et konkret tilf\u00e6lde.<\/p>\n<p><\/p>\n<p>Jeg vil anbefale, at du ogs\u00e5 ser p\u00e5 Alexey Milovids pr\u00e6sentation. Han fortalte for omkring en m\u00e5ned siden om optimeringer i ClickHouse til specifikke specialiseringer. Han forklarer netop, at i almindelighed er C++-implementeringen eller en anden implementering designet til at fungere godt i gennemsnit. Den kan fungere d\u00e5rligere end en specialiseret implementering baseret p\u00e5 specifik viden, som vores, n\u00e5r vi ved, at de \u00f8verste 32 bits stort set er konstante.<\/p>\n<p><\/p>\n<p><em>Jeg har et andet sp\u00f8rgsm\u00e5l. Hvad er den grundl\u00e6ggende forskel fra InfluxDB?<\/em><\/p>\n<p><\/p>\n<p>Der er mange grundl\u00e6ggende forskelle. N\u00e5r det g\u00e6lder ydeevne og hukommelsesforbrug, viser InfluxDB i testene en 10 gange st\u00f8rre hukommelsesforbrug for high cardinality tidsserier, n\u00e5r der er mange, for eksempel millioner. For eksempel bruger VictoriaMetrics 1 GB p\u00e5 en million aktive serier, mens InfluxDB p\u00e5 den anden side bruger 10 Gb. Og det er en stor forskel. <\/p>\n<p><\/p>\n<p>Den anden grundl\u00e6ggende forskel er, at InfluxDB har m\u00e6rkelige foresp\u00f8rgselssprog \u2013 Flux og InfluxQL. De er ikke s\u00e6rlig bekvemme til at arbejde med tidsserier sammenlignet med <noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/@valyala\/promql-tutorial-for-beginners-9ab455142085\">PromQL<\/a><\/noindex>, som underst\u00f8ttes i VictoriaMetrics. PromQL er foresp\u00f8rgselssproget fra Prometheus.<\/p>\n<p><\/p>\n<p>Og en anden forskel er, at InfluxDB har en lidt m\u00e6rkelig datamodel, hvor hver linje kan indeholde flere fields med forskellige s\u00e6t tags. Disse linjer deles yderligere op i forskellige tabeller. Disse ekstra komplikationer g\u00f8r det sv\u00e6rere at arbejde med denne database. Den er sv\u00e6r at vedligeholde og forst\u00e5.<\/p>\n<p><\/p>\n<p>I VictoriaMetrics er alt meget enklere. Hver tidsserie repr\u00e6senterer et n\u00f8gle-v\u00e6rdi-par. V\u00e6rdien er et s\u00e6t punkter \u2013 <code>(timestamp, v\u00e6rdi)<\/code>, mens n\u00f8glen er et s\u00e6t <code>label=value<\/code>. Der er ingen opdeling i fields og measurements. Dette giver dig mulighed for at v\u00e6lge vilk\u00e5rlige data og derefter kombinere, tilf\u00f8je, tr\u00e6kke fra, multiplicere, dividere, i mods\u00e6tning til InfluxDB, hvor beregninger mellem forskellige r\u00e6kker stadig ikke er implementeret, s\u00e5 vidt jeg ved. Selvom de er implementeret, er de vanskelige, man skal skrive en masse kode. <\/p>\n<p><\/p>\n<p><em>Jeg har et opklarende sp\u00f8rgsm\u00e5l. Forstod jeg rigtigt, at der var et eller andet problem, som du fortalte om, at denne inverterede indeks ikke kunne v\u00e6re i hukommelsen, s\u00e5 der er partitionering?<\/em><\/p>\n<p><\/p>\n<p>I starten viste jeg en naiv implementering af den inverterede indeks p\u00e5 en standard Go-map. En s\u00e5dan implementering er ikke egnet til databaser, fordi dette inverterede indeks ikke gemmes p\u00e5 disken, og databasen skal gemme p\u00e5 disken, s\u00e5 disse data forbliver tilg\u00e6ngelige ved genstart. I denne implementering vil det inverterede indeks forsvinde ved genstart af applikationen. Og du vil miste adgangen til alle data, fordi du ikke kan finde dem. <\/p>\n<p><\/p>\n<p><em>Hej! Tak for din pr\u00e6sentation! Jeg hedder Pavel. Jeg kommer fra virksomheden Wildberries. Jeg har et par sp\u00f8rgsm\u00e5l til dig. Det f\u00f8rste sp\u00f8rgsm\u00e5l. Hvordan ville du mene, hvis du havde valgt en anden princip m\u00e5de at opbygge arkitekturen for din applikation og partitioneret dataene efter tid, s\u00e5 kunne du muligvis g\u00f8re krydsning af data under s\u00f8gningen, udelukkende baseret p\u00e5, at der i \u00e9n partition er data for \u00e9t tidsrum, alts\u00e5 for et tidsinterval, og du ikke skulle bekymre dig om, at du har fragmenter spredt forskelligt? Sp\u00f8rgsm\u00e5l nummer 2 - da du implementerer en s\u00e5dan algoritme med bitset og alt det andet, har du m\u00e5ske pr\u00f8vet at bruge processorinstruktioner? M\u00e5ske har du pr\u00f8vet s\u00e5danne optimeringer?<\/em><\/p>\n<p><\/p>\n<p>Svar p\u00e5 det andet sp\u00f8rgsm\u00e5l med det samme. Vi er ikke kommet s\u00e5 langt endnu. Men hvis det er n\u00f8dvendigt, s\u00e5 vil vi. Og det f\u00f8rste, hvad var sp\u00f8rgsm\u00e5let?<\/p>\n<p><\/p>\n<p><em>Du diskuterede to scenarier. Og sagde, at du valgte den anden med en mere kompleks implementering. Og du foretrak ikke den f\u00f8rste, hvor dataene er partitioneret efter tid.<\/em> <\/p>\n<p><\/p>\n<p>Ja. I det f\u00f8rste tilf\u00e6lde ville den samlede m\u00e6ngde af indekset v\u00e6re st\u00f8rre, fordi vi i hver partition skulle opbevare dubletter af data for de tidsserier, der str\u00e6kker sig over alle disse partitioner. Og hvis din churn rate for tidsserierne er lav, dvs. de samme r\u00e6kker konstant bruges, ville vi i f\u00f8rste tilf\u00e6lde tabe meget mere plads i forhold til den anden mulighed.<\/p>\n<p><\/p>\n<p>S\u00e5 ja, tidspartitionering er en god mulighed. Den bruges af Prometheus. Men der er en anden ulempe ved Prometheus. N\u00e5r den sammenl\u00e6gger disse datastykkere, skal den holde metadata om alle labels og tidsserier i hukommelsen. Derfor, hvis datastykkene er store, som den sammenl\u00e6gger, vokser hukommelsesforbruget meget under sammenl\u00e6gningen, i mods\u00e6tning til VictoriaMetrics. Ved sammenl\u00e6gning bruger VictoriaMetrics slet ikke hukommelse, kun et par kilobyte, uanset st\u00f8rrelsen p\u00e5 de sammenlagte datastykkene.<\/p>\n<p><\/p>\n<p><em>Algoritmen, som du bruger, anvender hukommelse. I den markeres tidsserie-tags med v\u00e6rdier. Og p\u00e5 den m\u00e5de tjekker du for parret tilstedev\u00e6relse i et datas\u00e6t og i et andet. Og forst\u00e5r, om der er sket et intersect eller ej. Normalt implementerer databaser cursorer, iteratorer, der gemmer deres nuv\u00e6rende tilstand og l\u00f8ber gennem de sorterede data, hvilket giver en simpel kompleksitet for de operationer.<\/em> <\/p>\n<p><\/p>\n<p>Hvorfor bruger vi ikke cursorer til at krydse data?<\/p>\n<p><\/p>\n<p><em>Ja.<\/em> <\/p>\n<p><\/p>\n<p>I vores LevelDB eller i mergeset gemmes der netop sorterede r\u00e6kker. Vi kan bruge en cursor til at finde intersection. Men hvorfor bruge det? Fordi det er langsomt. Fordi cursorer indeb\u00e6rer, at der for hver r\u00e6kke skal kald en funktion. Funktionsopkaldet tager 5 nanosekunder. Og hvis du har 100.000.000 r\u00e6kker, ender det med, at vi bruger et halvt sekund bare p\u00e5 funktionskald.<\/p>\n<p><\/p>\n<p><em>Ja, det findes. Og jeg har et sidste sp\u00f8rgsm\u00e5l. Sp\u00f8rgsm\u00e5let kan m\u00e5ske lyde lidt underligt. Hvorfor kan man ikke, n\u00e5r dataene kommer ind, beregne alle n\u00f8dvendige aggregationer og gemme dem i den n\u00f8dvendige form? Hvorfor gemme enorme m\u00e6ngder i systemer som VictoriaMetrics, ClickHouse mv., for derefter at bruge meget tid p\u00e5 dem?<\/em><\/p>\n<p><\/p>\n<p><em>Jeg vil give et eksempel, s\u00e5 det bliver mere klart. Antag, hvordan fungerer en lille leget\u00f8js speedometer? Det registrerer afstanden, du har tilbagelagt, ved hele tiden at tilf\u00f8je den til den ene v\u00e6rdi og tiden til den anden. Og s\u00e5 dividerer det. Og f\u00e5r gennemsnitshastigheden. Man kan g\u00f8re n\u00e6sten det samme. Samle alle n\u00f8dvendige fakta undervejs.<\/em><\/p>\n<p><\/p>\n<p>Okay, jeg forst\u00e5r sp\u00f8rgsm\u00e5let. Dit eksempel har relevans. Hvis du ved, hvilke aggregeringer du har brug for, er det den bedste implementering. Men problemet er, at folk gemmer disse metrikker, nogle data i ClickHouse, og de ved endnu ikke, hvordan de vil aggregere, filtrere dem i fremtiden, s\u00e5 de er n\u00f8dt til at gemme alle r\u00e5data. Men hvis du ved, at du skal t\u00e6lle noget gennemsnitligt, hvorfor s\u00e5 ikke t\u00e6lle det, i stedet for at gemme en masse r\u00e5 v\u00e6rdier der? Men det er kun, hvis du helt pr\u00e6cist ved, hvad du har brug for.<\/p>\n<p><\/p>\n<p>For \u00f8vrigt underst\u00f8tter databaser til opbevaring af tidsserier beregningen af aggregeringer. For eksempel underst\u00f8tter Prometheus <noindex><a rel=\"nofollow\" href=\"https:\/\/prometheus.io\/docs\/prometheus\/latest\/configuration\/recording_rules\/\">optagelsesregler<\/a><\/noindex>. Dvs. det kan g\u00f8res, hvis du ved, hvilke aggregeringer du f\u00e5r brug for. VictoriaMetrics har ikke dette endnu, men Prometheus placeres normalt foran den, hvor du kan g\u00f8re det i optagelsesreglerne.<\/p>\n<p><\/p>\n<p>For eksempel, p\u00e5 det tidligere job skulle jeg t\u00e6lle antallet af h\u00e6ndelser i et glidende vindue over den sidste time. Problemet var, at jeg m\u00e5tte lave en brugerdefineret implementering i Go, dvs. en tjeneste til at t\u00e6lle denne ting. Denne tjeneste viste sig at v\u00e6re ikke triviel, fordi det er sv\u00e6rt at t\u00e6lle. Implementeringen kan v\u00e6re enkel, hvis du kun skal t\u00e6lle nogle aggregeringer p\u00e5 faste tidsintervaller. Men hvis du vil t\u00e6lle h\u00e6ndelser i et glidende vindue, er det ikke s\u00e5 enkelt, som det ser ud. Jeg tror ikke, det er blevet implementeret endnu i ClickHouse eller i tidsseriedatabaser, fordi det er sv\u00e6rt at implementere.<\/p>\n<p><\/p>\n<p><em>Og s\u00e5 et sp\u00f8rgsm\u00e5l mere. Vi har lige talt om gennemsnit, og jeg kom i tanke om, at der engang var noget som Graphite med backend Carbon. Og den kunne udtynde gamle data, dvs. efterlade \u00e9t punkt pr. minut, \u00e9t punkt pr. time osv. I princippet er det ret praktisk, hvis vi har brug for r\u00e5data, lad os sige, for en m\u00e5ned, og alt det andet kan udtyndes. Men Prometheus og VictoriaMetrics underst\u00f8tter ikke denne funktionalitet. Er det planlagt at underst\u00f8tte det? Hvis ikke, hvorfor?<\/em><\/p>\n<p><\/p>\n<p>Tak for sp\u00f8rgsm\u00e5let. Vores brugere sp\u00f8rger om dette fra tid til anden. De sp\u00f8rger, hvorn\u00e5r vi tilf\u00f8jer st\u00f8tte til nedpr\u00f8vning (downsampling). Der er flere problemer her. For det f\u00f8rste forst\u00e5r hver bruger det som <code>downsampling<\/code> noget forskelligt: nogle \u00f8nsker at f\u00e5 et vilk\u00e5rligt punkt inden for et givet interval, andre \u00f8nsker maksimale, minimale og gennemsnitlige v\u00e6rdier. Hvis flere systemer skriver data til din database, kan man ikke behandle dem ensartet. Det kan vise sig, at der for hvert system skal bruges forskellige nedpr\u00f8vningsmetoder. Og det er sv\u00e6rt at implementere.<\/p>\n<p><\/p>\n<p>Og for det andet er VictoriaMetrics, ligesom ClickHouse, optimeret til at arbejde med store m\u00e6ngder r\u00e5data, s\u00e5 den kan behandle en milliard linjer p\u00e5 mindre end et sekund, hvis du har mange kerner i dit system. Scanning af tidsseriepunkter i VictoriaMetrics er 50.000.000 punkter per sekund pr. kerne. Og denne ydeevne skalerer med de tilg\u00e6ngelige kerner. Det vil sige, hvis du har 20 kerner, f\u00e5r du for eksempel scanning af en milliard punkter per sekund. Og denne egenskab ved VictoriaMetrics og ClickHouse reducerer behovet for nedpr\u00f8vning.<\/p>\n<p><\/p>\n<p>En anden egenskab er, at VictoriaMetrics effektivt komprimerer disse data. Komprimering ligger i gennemsnit fra 0,4 til 0,8 byte pr. punkt i produktion. Hvert punkt best\u00e5r af et tidsstempel + v\u00e6rdi. Og det komprimeres til mindre end en byte i gennemsnit. <\/p>\n<p><\/p>\n<p><em>Sergej. Jeg har et sp\u00f8rgsm\u00e5l. Hvad er den mindste tidskvantum for registrering?<\/em><\/p>\n<p><\/p>\n<p>En millisekund. For nylig havde vi en samtale med andre databaseudviklere for tidsserier. Deres minimale tidskvantum er et sekund. I Graphite, for eksempel, er det ogs\u00e5 et sekund. I OpenTSDB er det ogs\u00e5 et sekund. I InfluxDB \u2013 nanosekund pr\u00e6cision. I VictoriaMetrics \u2013 en millisekund, fordi det er en millisekund i Prometheus. VictoriaMetrics blev oprindeligt udviklet som en remote storage for Prometheus. Men nu kan den ogs\u00e5 gemme data fra andre systemer. <\/p>\n<p><\/p>\n<p>Manden, jeg talte med, siger, at de har sekund\u00e6r pr\u00e6cision \u2014 det er tilstr\u00e6kkeligt for dem, fordi det afh\u00e6nger af den type data, der gemmes i tidsseriedatabasen. Hvis det er DevOps-data eller data fra infrastruktur, hvor du indsamler dem med et interval p\u00e5 30 sekunder til et minut, er sekund\u00e6r pr\u00e6cision tilstr\u00e6kkeligt, der er ikke behov for noget mindre. Men hvis du indsamler disse data fra h\u00f8jfrekvente handelssystemer, kr\u00e6ves der nanosekund pr\u00e6cision.<\/p>\n<p><\/p>\n<p>Millisekunders pr\u00e6cision i VictoriaMetrics er egnet til b\u00e5de DevOps-sager og kan v\u00e6re passende for de fleste de tilf\u00e6lde, jeg n\u00e6vnte i starten af pr\u00e6sentationen. Det eneste, det m\u00e5ske ikke er velegnet til, er high-frequency trading systemer.<\/p>\n<p><\/p>\n<p><em>Tak! Og endnu et sp\u00f8rgsm\u00e5l. Hvad er kompatibiliteten i PromQL?<\/em><\/p>\n<p><\/p>\n<p>Fuld bagudkompatibilitet. VictoriaMetrics underst\u00f8tter fuldt ud PromQL. Derudover tilf\u00f8jer det ogs\u00e5 yderligere udvidet funktionalitet til PromQL kaldet <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/VictoriaMetrics\/VictoriaMetrics\/wiki\/MetricsQL\">MetricsQL<\/a><\/noindex>. Med hensyn til denne udvidede funktionalitet er der et foredrag p\u00e5 YouTube. Jeg talte om det ved Monitoring Meetup i for\u00e5ret i Sankt Petersborg.<\/p>\n<p><\/p>\n<p>Telegram-kanal <noindex><a rel=\"nofollow\" href=\"https:\/\/t.me\/VictoriaMetrics_ru1\">VictoriaMetrics<\/a><\/noindex>.<\/p>\n<p class=\"for_users_only_msg\">Kun registrerede brugere kan deltage i unders\u00f8gelsen. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Log ind<\/a><\/noindex>, please.<\/p>\n<h2 class=\"default-block__polling-title\">Hvad forhindrer dig i at g\u00e5 over til VictoriaMetrics som en langsigtet opbevaring for Prometheus? (Skriv i kommentarer, jeg tilf\u00f8jer det til afstemningen))<\/h2>\n<ul class=\"poll-result\">\n<li class=\"poll-result__item\">\n<p>                <strong class=\"poll-result__data-percent  poll-result__data-percent_winner\">71,4%<\/strong>Bruger ikke Prometheus5<\/p>\n<\/li>\n<li class=\"poll-result__item\">\n<p>                <strong class=\"poll-result__data-percent\">28,6%<\/strong>Vidste ikke om VictoriaMetrics2<\/p>\n<\/li>\n<\/ul>\n<p>    7 brugere har stemt. 12 brugere har undladt at stemme.<br \/>\n<br \/>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/500844\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot; VictoriaMetrics \u2014 \u0431\u044b\u0441\u0442\u0440\u0430\u044f \u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u0430\u044f \u0421\u0423\u0411\u0414 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430 (\u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u043d\u0430\u0431\u043e\u0440 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u044d\u0442\u043e\u043c\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0447\u0435\u0440\u0435\u0437 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043e\u043f\u0440\u043e\u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u043b\u0438 \u0441\u0431\u043e\u0440 \u043c\u0435\u0442\u0440\u0438\u043a). \u0412\u043e\u0442 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0432\u0438\u0434\u0435\u043e \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u2014 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":80734,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-80733","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47Go optimizations in VictoriaMetrics. \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-08T11:42:31+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-08T11:42:31+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Go optimeringer i VictoriaMetrics. Alexander Valjalkin | ProHoster","description":"Jeg vil gerne pr\u00e6sentere en gennemgang af rapporten fra slutningen af 2019 af Alexander Valyalkin \"Go-optimeringer i VictoriaMetrics\"","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47Go optimizations in VictoriaMetrics. \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043a\u043e\u043d\u0446\u0430 2019 \u0433\u043e\u0434\u0430 \u0410\u043b\u0435\u043a\u0441\u0430\u043d\u0434\u0440\u0430 \u0412\u0430\u043b\u044f\u043b\u043a\u0438\u043d\u0430 &quot;Go optimizations in VictoriaMetrics&quot;","og:url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/go-optimizations-in-victoriametrics-aleksandr-valyalkin","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-08T11:42:31+00:00","article:modified_time":"2020-05-08T11:42:31+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"80733","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:12:22","updated":"2022-09-29 05:16:51","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/80733","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=80733"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/80733\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/80734"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=80733"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=80733"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=80733"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}