Datakomprimering i Apache Ignite. Sbers oplevelse

Datakomprimering i Apache Ignite. Sbers oplevelseNår du arbejder med store mængder data, kan problemet med mangel på diskplads nogle gange opstå. En måde at løse dette problem på er komprimering, takket være hvilken du på det samme udstyr har råd til at øge lagervolumen. I denne artikel vil vi se på, hvordan datakomprimering fungerer i Apache Ignite. Denne artikel vil kun beskrive diskkomprimeringsmetoderne implementeret i produktet. Andre metoder til datakomprimering (over netværket, i hukommelsen), uanset om de er implementeret eller ej, forbliver uden for rammerne.

Så med persistenstilstand aktiveret, som et resultat af ændringer i data i cachen, begynder Ignite at skrive til disken:

  1. Indhold af caches
  2. Write Ahead Log (i det følgende blot WAL)

Der har været en mekanisme til WAL-komprimering i et stykke tid nu, kaldet WAL-komprimering. Den nyligt udgivne Apache Ignite 2.8 introducerede yderligere to mekanismer, der giver dig mulighed for at komprimere data på disken: disksidekomprimering til at komprimere indholdet af caches og WAL-sidesnapshot-komprimering til at komprimere nogle WAL-indgange. Flere detaljer om alle tre af disse mekanismer nedenfor.

Disksidekomprimering

Hvordan fungerer denne her

Lad os først tage et meget kort kig på, hvordan Ignite gemmer data. Sidehukommelse bruges til opbevaring. Sidestørrelsen indstilles i starten af ​​noden og kan ikke ændres på senere stadier; sidestørrelsen skal også være en potens af to og et multiplum af filsystemets blokstørrelse. Sider indlæses i RAM fra disk efter behov; størrelsen af ​​data på disken kan overstige mængden af ​​allokeret RAM. Hvis der ikke er nok plads i RAM til at indlæse en side fra disken, vil gamle, ikke længere brugte sider blive smidt ud af RAM.

Dataene gemmes på disken i følgende form: Der oprettes en separat fil for hver partition i hver cachegruppe; i denne fil vises siderne efter hinanden i stigende indeksrækkefølge. Helside-id'et indeholder cachegruppe-id'et, partitionsnummeret og sideindekset i filen. Ved at bruge fuldside-id'en kan vi således entydigt bestemme filen og forskydningen i filen for hver side. Du kan læse mere om personsøgningshukommelse i Apache Ignite Wiki-artiklen: Ignite Persistent Store - under motorhjelmen.

Disksidekomprimeringsmekanismen, som du måske kan gætte ud fra navnet, fungerer på sideniveau. Når denne mekanisme er aktiveret, behandles data i RAM som de er, uden nogen komprimering, men når sider gemmes fra RAM til disk, komprimeres de.

Men at komprimere hver side individuelt er ikke en løsning på problemet; du skal på en eller anden måde reducere størrelsen på de resulterende datafiler. Hvis sidestørrelsen ikke længere er fast, kan vi ikke længere skrive sider til filen efter hinanden, da dette kan skabe en række problemer:

  • Ved hjælp af sideindekset vil vi ikke være i stand til at beregne den offset, som den er placeret med i filen.
  • Det er ikke klart, hvad man skal gøre med sider, der ikke er i slutningen af ​​filen og ændre deres størrelse. Hvis sidestørrelsen mindskes, forsvinder den frigjorte plads. Hvis sidestørrelsen øges, skal du lede efter et nyt sted i filen for det.
  • Hvis en side bevæger sig med et antal bytes, der ikke er et multiplum af filsystemets blokstørrelse, vil læsning eller skrivning af den kræve, at du berører endnu en filsystemblok, hvilket kan føre til ydeevneforringelse.

For at undgå at løse disse problemer på sit eget niveau bruger disksidekomprimering i Apache Ignite en filsystemmekanisme kaldet sparse filer. En sparsom fil er en, hvor nogle nul-fyldte områder kan markeres som "huller". I dette tilfælde vil ingen filsystemblokke blive tildelt til at gemme disse huller, hvilket resulterer i besparelser på diskplads.

Det er logisk, at for at frigøre en filsystemblok, skal størrelsen af ​​hullet være større end eller lig med filsystemblokken, hvilket pålægger en yderligere begrænsning på sidestørrelsen og Apache Ignite: for at komprimering skal have nogen effekt, sidestørrelsen skal være strengt taget større end størrelsen på filsystemblokken. Hvis sidestørrelsen er lig med blokstørrelsen, så vil vi aldrig kunne frigøre en enkelt blok, da for at frigøre en enkelt blok skal den komprimerede side optage 0 bytes. Hvis sidestørrelsen er lig med størrelsen på 2 eller 4 blokke, vil vi allerede kunne frigøre mindst én blok, hvis vores side er komprimeret til henholdsvis mindst 50 % eller 75 %.

Således den endelige beskrivelse af, hvordan mekanismen fungerer: Når man skriver en side til disk, forsøger man at komprimere siden. Hvis størrelsen af ​​den komprimerede side tillader en eller flere filsystemblokke at blive frigivet, skrives siden i komprimeret form, og der laves et "hul" i stedet for de frigjorte blokke (et systemkald udføres fallocate() med hulflaget). Hvis størrelsen på den komprimerede side ikke tillader blokkene at blive frigivet, gemmes siden som den er, ukomprimeret. Alle sideforskydninger beregnes på samme måde som uden komprimering, ved at gange sideindekset med sidestørrelsen. Ingen flytning af sider er påkrævet på egen hånd. Sideforskydninger, ligesom uden komprimering, falder på grænserne for filsystemblokke.

Datakomprimering i Apache Ignite. Sbers oplevelse

I den nuværende implementering kan Ignite kun arbejde med sparsomme filer under Linux OS; derfor kan disksidekomprimering kun aktiveres, når Ignite bruges på dette operativsystem.

Kompressionsalgoritmer, der kan bruges til disksidekomprimering: ZSTD, LZ4, Snappy. Derudover er der en driftstilstand (SKIP_GARBAGE), hvor kun ubrugt plads på siden bliver smidt ud uden at anvende komprimering på de resterende data, hvilket reducerer belastningen på CPU'en sammenlignet med de tidligere anførte algoritmer.

Effektivitet

Desværre foretog jeg ikke egentlige præstationsmålinger på rigtige stande, da vi ikke planlægger at bruge denne mekanisme i produktionen, men vi kan teoretisk spekulere i, hvor vi vil tabe, og hvor vi vinder.

For at gøre dette skal vi huske, hvordan sider læses og skrives, når de åbnes:

  • Når du udfører en læseoperation, søges den først i RAM; hvis søgningen mislykkes, indlæses siden i RAM fra disken af ​​den samme tråd, der udfører læsningen.
  • Når en skriveoperation udføres, markeres siden i RAM som snavset, men siden gemmes ikke fysisk på disken med det samme af tråden, der udfører skrivningen. Alle beskidte sider gemmes på disk senere i checkpoint-processen i separate tråde.

Så indvirkningen på læseoperationer er:

  • Positiv (disk IO), på grund af et fald i antallet af læste filsystemblokke.
  • Negativ (CPU) på grund af den ekstra belastning, der kræves af operativsystemet for at arbejde med sparsomme filer. Det er også muligt, at yderligere IO-operationer implicit vil dukke op her for at gemme en mere kompleks sparsom filstruktur (desværre er jeg ikke bekendt med alle detaljerne om, hvordan sparse filer fungerer).
  • Negativ (CPU), på grund af behovet for at dekomprimere sider.
  • Der er ingen indflydelse på skriveoperationer.
  • Indvirkning på checkpoint-processen (alt her ligner læseoperationer):
  • Positiv (disk IO), på grund af et fald i antallet af skrevne filsystemblokke.
  • Negativ (CPU, muligvis disk IO), på grund af arbejde med sparsomme filer.
  • Negativ (CPU), på grund af behovet for sidekomprimering.

Hvilken side af skalaen vil vippe skalaen? Alt dette afhænger meget af miljøet, men jeg er tilbøjelig til at tro, at komprimering af diskside højst sandsynligt vil føre til ydeevneforringelse på de fleste systemer. Desuden viser test på andre DBMS'er, der bruger en lignende tilgang med sparsomme filer, et fald i ydeevnen, når komprimering er aktiveret.

Sådan aktiveres og konfigureres

Som nævnt ovenfor er minimumsversionen af ​​Apache Ignite, der understøtter disksidekomprimering, 2.8, og kun Linux-operativsystemet understøttes. Aktiver og konfigurer som følger:

  • Der skal være et ignite-compression-modul i klassestien. Som standard er den placeret i Apache Ignite-distributionen i biblioteket libs/valgfri og er ikke inkluderet i klassestien. Du kan blot flytte mappen et niveau op til libs, og når du kører den gennem ignite.sh, bliver den automatisk aktiveret.
  • Persistens skal være aktiveret (Aktiveret via DataRegionConfiguration.setPersistenceEnabled(true)).
  • Sidestørrelsen skal være større end filsystemets blokstørrelse (du kan indstille den vha DataStorageConfiguration.setPageSize() ).
  • For hver cache, hvis data skal komprimeres, skal du konfigurere komprimeringsmetoden og (valgfrit) komprimeringsniveauet (metoder) CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

WAL komprimering

Hvordan fungerer denne her

Hvad er WAL, og hvorfor er det nødvendigt? Meget kort: dette er en log, der indeholder alle hændelser, der i sidste ende ændrer sidelagringen. Det er primært nødvendigt for at kunne komme sig i tilfælde af et fald. Enhver handling, før den giver brugeren kontrol, skal først registrere en hændelse i WAL, så den i tilfælde af fejl kan afspilles i loggen og gendannes alle operationer, som brugeren har modtaget et vellykket svar på, selv hvis disse operationer havde ikke tid til at blive afspejlet i sidelageret på disk (allerede ovenfor Det er blevet beskrevet, at selve skrivningen til sidelageret sker i en proces kaldet "checkpointing" med en vis forsinkelse af separate tråde).

Indtastninger i WAL er opdelt i logiske og fysiske. Booleske er nøglerne og værdierne i sig selv. Fysisk - afspejler ændringer på sider i sidebutikken. Mens logiske optegnelser kan være nyttige i nogle andre tilfælde, er fysiske optegnelser kun nødvendige til genopretning i tilfælde af et nedbrud, og optegnelser er kun nødvendige siden det sidste vellykkede kontrolpunkt. Her vil vi ikke gå i detaljer og forklare, hvorfor det virker på denne måde, men interesserede kan henvise til den allerede nævnte artikel om Apache Ignite Wiki: Ignite Persistent Store - under motorhjelmen.

Der er ofte flere fysiske poster pr. logisk post. Det vil sige, at for eksempel én put-operation i cachen påvirker flere sider i sidehukommelsen (en side med selve dataene, sider med indekser, sider med fri-lister). I nogle syntetiske test fandt jeg ud af, at fysiske poster optog op til 90% af WAL-filen. De er dog nødvendige i meget kort tid (som standard er intervallet mellem kontrolpunkter 3 minutter). Det ville være logisk at slippe af med disse data efter at have mistet deres relevans. Det er præcis, hvad WAL-komprimeringsmekanismen gør: den fjerner fysiske poster og komprimerer de resterende logiske poster ved hjælp af zip, mens filstørrelsen reduceres meget betydeligt (nogle gange med titusindvis af gange).

Fysisk består WAL af flere segmenter (10 som standard) af en fast størrelse (64MB som standard), som overskrives på en cirkulær måde. Så snart det aktuelle segment er udfyldt, tildeles det næste segment som aktuelt, og det udfyldte segment kopieres til arkivet af en separat tråd. WAL-komprimering fungerer allerede med arkivsegmenter. Som en separat tråd overvåger den også udførelsen af ​​kontrolpunktet og begynder komprimering i arkivsegmenter, for hvilke der ikke længere er brug for fysiske poster.

Datakomprimering i Apache Ignite. Sbers oplevelse

Effektivitet

Da WAL-komprimering kører som et separat gevind, bør der ikke være nogen direkte indflydelse på de operationer, der udføres. Men det lægger stadig ekstra baggrundsbelastning på CPU'en (komprimering) og disken (læser hvert WAL-segment fra arkivet og skriver de komprimerede segmenter), så hvis systemet kører på sin maksimale kapacitet, vil det også føre til ydeevneforringelse.

Sådan aktiveres og konfigureres

Du kan aktivere WAL-komprimering ved hjælp af egenskaben WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Ved hjælp af metoden DataStorageConfiguration.setWalCompactionLevel() kan du også indstille komprimeringsniveauet, hvis du ikke er tilfreds med standardværdien (BEST_SPEED).

WAL side snapshot komprimering

Hvordan fungerer denne her

Vi har allerede fundet ud af, at i WAL er poster opdelt i logiske og fysiske. For hver ændring af hver side genereres en fysisk WAL-post i sidehukommelsen. Fysiske poster er til gengæld også opdelt i 2 undertyper: sidesnapshot record og delta record. Hver gang vi ændrer noget på en side og overfører det fra en ren tilstand til en beskidt tilstand, gemmes en komplet kopi af denne side i WAL (page snapshot record). Selvom vi kun ændrede én byte i WAL, vil posten være lidt større end sidestørrelsen. Hvis vi ændrer noget på en allerede beskidt side, dannes der en delta-record i WAL, som kun afspejler ændringer i forhold til sidens tidligere tilstand, men ikke hele siden. Da nulstilling af sidernes tilstand fra beskidte til rene udføres under checkpoint-processen, umiddelbart efter starten af ​​checkpointet, vil næsten alle fysiske poster kun bestå af snapshots af sider (da alle sider umiddelbart efter starten af ​​checkpointet er rene). , så når vi nærmer os det næste kontrolpunkt, begynder delta-registreringsfraktionen at vokse og nulstilles igen i begyndelsen af ​​det næste kontrolpunkt. Målinger i nogle syntetiske test viste, at andelen af ​​sidesnapshots i den samlede mængde fysiske poster når op på 90 %.

Ideen med WAL-sidesnapshotkomprimering er at komprimere sidesnapshots ved hjælp af et færdiglavet sidekomprimeringsværktøj (se disksidekomprimering). Samtidig, i WAL, gemmes poster sekventielt i kun tilføjelsestilstand, og der er ingen grund til at binde poster til grænserne for filsystemblokke, så her, i modsætning til disksidekomprimeringsmekanismen, har vi ikke brug for sparsomme filer på alle; derfor vil denne mekanisme ikke kun fungere på OS Linux. Derudover er det ikke længere ligegyldigt for os, hvor meget vi var i stand til at komprimere siden. Selvom vi frigav 1 byte, er dette allerede et positivt resultat, og vi kan gemme komprimerede data i WAL, i modsætning til disksidekomprimering, hvor vi kun gemmer den komprimerede side, hvis vi frigjorde mere end 1 filsystemblok.

Sider er meget komprimerbare data, deres andel af den samlede WAL-volumen er meget høj, så uden at ændre WAL-filformatet kan vi få en betydelig reduktion i dens størrelse. Komprimering, herunder logiske poster, vil kræve en ændring i format og tab af kompatibilitet, for eksempel for eksterne forbrugere, der kan være interesserede i logiske poster, men vil ikke føre til en væsentlig reduktion i filstørrelsen.

Som med disksidekomprimering kan WAL-sidesnapshot-komprimering bruge ZSTD, LZ4, Snappy-komprimeringsalgoritmer samt SKIP_GARBAGE-tilstanden.

Effektivitet

Det er ikke svært at bemærke, at direkte aktivering af WAL-sidesnapshot-komprimering kun påvirker tråde, der skriver data til sidehukommelsen, det vil sige de tråde, der ændrer data i caches. Aflæsning af fysiske poster fra WAL sker kun én gang, i det øjeblik noden hæves efter et fald (og kun hvis den falder under et kontrolpunkt).

Dette påvirker tråde, der ændrer data på følgende måde: vi får en negativ effekt (CPU) på grund af behovet for at komprimere siden hver gang før skrivning til disk, og en positiv effekt (disk IO) på grund af en reduktion i mængden af data skrevet. Derfor er alt simpelt her: Hvis systemets ydeevne er begrænset af CPU'en, får vi en lille forringelse, hvis den er begrænset af disk I/O, får vi en stigning.

Indirekte påvirker reduktion af WAL-størrelsen også (positivt) strømme, der dumper WAL-segmenter i arkiv- og WAL-komprimeringsstrømmene.

Reelle præstationstests i vores miljø ved hjælp af syntetiske data viste en lille stigning (gennemstrømning steg med 10%-15%, latens faldt med 10%-15%).

Sådan aktiveres og konfigureres

Minimum Apache Ignite version: 2.8. Aktiver og konfigurer som følger:

  • Der skal være et ignite-compression-modul i klassestien. Som standard er den placeret i Apache Ignite-distributionen i biblioteket libs/valgfri og er ikke inkluderet i klassestien. Du kan blot flytte mappen et niveau op til libs, og når du kører den gennem ignite.sh, bliver den automatisk aktiveret.
  • Persistens skal være aktiveret (Aktiveret via DataRegionConfiguration.setPersistenceEnabled(true)).
  • Kompressionstilstanden skal indstilles ved hjælp af metoden DataStorageConfiguration.setWalPageCompression(), komprimering er deaktiveret som standard (DISABLED-tilstand).
  • Du kan eventuelt indstille komprimeringsniveauet ved hjælp af metoden DataStorageConfiguration.setWalPageCompression(), se javadoc for metoden for gyldige værdier for hver tilstand.

Konklusion

De overvejede datakomprimeringsmekanismer i Apache Ignite kan bruges uafhængigt af hinanden, men enhver kombination af dem er også acceptabel. At forstå, hvordan de fungerer, vil give dig mulighed for at bestemme, hvor egnede de er til dine opgaver i dit miljø, og hvad du skal ofre, når du bruger dem. Disksidekomprimering er designet til at komprimere hovedlageret og kan give et medium komprimeringsforhold. WAL side snapshot komprimering vil give en gennemsnitlig grad af komprimering for WAL filer, og vil højst sandsynligt endda forbedre ydeevnen. WAL-komprimering vil ikke have en positiv effekt på ydeevnen, men vil reducere størrelsen af ​​WAL-filer så meget som muligt ved at fjerne fysiske poster.

Kilde: www.habr.com

Tilføj en kommentar