Datakomprimering i Apache Ignite. Sbers erfaring

Datakomprimering i Apache Ignite. Sbers erfaringNår du arbeider med store datamengder, kan problemet med mangel på diskplass noen ganger oppstå. En måte å løse dette problemet på er komprimering, takket være at du på samme utstyr har råd til å øke lagringsvolumene. I denne artikkelen skal vi se på hvordan datakomprimering fungerer i Apache Ignite. Denne artikkelen vil kun beskrive diskkomprimeringsmetodene som er implementert i produktet. Andre metoder for datakomprimering (over nettverket, i minnet), enten de er implementert eller ikke, vil forbli utenfor omfanget.

Så, med utholdenhetsmodus aktivert, som et resultat av endringer i data i cachene, begynner Ignite å skrive til disk:

  1. Innhold i cacher
  2. Write Ahead Log (heretter bare WAL)

Det har vært en mekanisme for WAL-komprimering i ganske lang tid nå, kalt WAL-komprimering. Den nylig utgitte Apache Ignite 2.8 introduserte ytterligere to mekanismer som lar deg komprimere data på disk: disksidekomprimering for å komprimere innholdet i cacher og WAL-sides snapshot-komprimering for å komprimere noen WAL-oppføringer. Mer informasjon om alle disse tre mekanismene nedenfor.

Disksidekomprimering

Hvordan fungerer det

Først, la oss ta en veldig kort titt på hvordan Ignite lagrer data. Sideminne brukes til lagring. Sidestørrelsen angis ved starten av noden og kan ikke endres på senere stadier; sidestørrelsen må også være en potens av to og et multiplum av filsystemets blokkstørrelse. Sider lastes inn i RAM fra disk etter behov; størrelsen på data på disken kan overstige mengden tildelt RAM. Hvis det ikke er nok plass i RAM til å laste en side fra disk, vil gamle sider som ikke lenger brukes, bli kastet ut av RAM.

Dataene lagres på disken i følgende form: en separat fil opprettes for hver partisjon i hver cachegruppe; i denne filen vises sidene etter hverandre i stigende indeksrekkefølge. Helsideidentifikatoren inneholder buffergruppeidentifikatoren, partisjonsnummeret og sideindeksen i filen. Ved å bruke fullsideidentifikatoren kan vi derfor unikt bestemme filen og forskyvningen i filen for hver side. Du kan lese mer om personsøkerminne i Apache Ignite Wiki-artikkelen: Ignite Persistent Store - under panseret.

Disksidekomprimeringsmekanismen, som du kanskje gjetter ut fra navnet, fungerer på sidenivå. Når denne mekanismen er aktivert, behandles data i RAM som de er, uten noen komprimering, men når sider lagres fra RAM til disk, blir de komprimert.

Men å komprimere hver side individuelt er ikke en løsning på problemet; du må på en eller annen måte redusere størrelsen på de resulterende datafilene. Hvis sidestørrelsen ikke lenger er fast, kan vi ikke lenger skrive sider til filen etter hverandre, siden dette kan skape en rekke problemer:

  • Ved å bruke sideindeksen vil vi ikke kunne beregne forskyvningen som den ligger i filen med.
  • Det er ikke klart hva du skal gjøre med sider som ikke er på slutten av filen og endre størrelsen. Hvis sidestørrelsen reduseres, forsvinner plassen den frigjorde. Hvis sidestørrelsen øker, må du se etter et nytt sted i filen for det.
  • Hvis en side beveger seg med et antall byte som ikke er et multiplum av filsystemblokkstørrelsen, vil lesing eller skriving av den kreve å berøre en filsystemblokk til, noe som kan føre til ytelsesforringelse.

For å unngå å løse disse problemene på sitt eget nivå, bruker disksidekomprimering i Apache Ignite en filsystemmekanisme kalt sparsomme filer. En sparsom fil er en der noen nullfylte områder kan merkes som "hull". I dette tilfellet vil ingen filsystemblokker bli tildelt for å lagre disse hullene, noe som resulterer i besparelser på diskplass.

Det er logisk at for å frigjøre en filsystemblokk, må størrelsen på hullet være større enn eller lik filsystemblokken, noe som legger en ekstra begrensning på sidestørrelsen og Apache Ignite: for at komprimering skal ha noen effekt, sidestørrelsen må være strengt tatt større enn størrelsen på filsystemblokken. Hvis sidestørrelsen er lik blokkstørrelsen, vil vi aldri kunne frigjøre en enkelt blokk, siden for å frigjøre en enkelt blokk, må den komprimerte siden oppta 0 byte. Hvis sidestørrelsen er lik størrelsen på 2 eller 4 blokker, vil vi allerede kunne frigjøre minst én blokk hvis siden vår er komprimert til henholdsvis minst 50 % eller 75 %.

Dermed den endelige beskrivelsen av hvordan mekanismen fungerer: Når man skriver en side til disk, forsøker man å komprimere siden. Hvis størrelsen på den komprimerte siden tillater at én eller flere filsystemblokker frigjøres, skrives siden i komprimert form, og det lages et "hull" i stedet for de frigjorte blokkene (et systemanrop utføres fallocate() med punch hole-flagget). Hvis størrelsen på den komprimerte siden ikke tillater at blokkene frigjøres, lagres siden som den er, ukomprimert. Alle sideforskyvninger beregnes på samme måte som uten komprimering, ved å multiplisere sideindeksen med sidestørrelsen. Ingen flytting av sider er nødvendig på egen hånd. Sideforskyvninger, akkurat som uten komprimering, faller på grensene til filsystemblokker.

Datakomprimering i Apache Ignite. Sbers erfaring

I den nåværende implementeringen kan Ignite bare fungere med sparsomme filer under Linux OS; følgelig kan disksidekomprimering bare aktiveres når du bruker Ignite på dette operativsystemet.

Komprimeringsalgoritmer som kan brukes til disksidekomprimering: ZSTD, LZ4, Snappy. I tillegg er det en driftsmodus (SKIP_GARBAGE), der kun ubrukt plass på siden blir kastet ut uten å bruke komprimering på gjenværende data, noe som reduserer belastningen på CPU sammenlignet med de tidligere listede algoritmene.

Ytelsespåvirkning

Dessverre foretok jeg ikke faktiske ytelsesmålinger på ekte stands, siden vi ikke planlegger å bruke denne mekanismen i produksjonen, men vi kan teoretisk spekulere hvor vi taper og hvor vi vinner.

For å gjøre dette må vi huske hvordan sider leses og skrives når de åpnes:

  • Når du utfører en leseoperasjon, søkes den først i RAM; hvis søket mislykkes, lastes siden inn i RAM fra disken av den samme tråden som utfører lesingen.
  • Når en skriveoperasjon utføres, merkes siden i RAM som skitten, men siden lagres ikke fysisk på disk umiddelbart av tråden som utfører skrivingen. Alle skitne sider lagres på disk senere i sjekkpunktprosessen i separate tråder.

Så innvirkningen på leseoperasjoner er:

  • Positiv (disk IO), på grunn av en reduksjon i antall leste filsystemblokker.
  • Negativ (CPU), på grunn av den ekstra belastningen som kreves av operativsystemet for å jobbe med sparsomme filer. Det er også mulig at ytterligere IO-operasjoner implisitt vil dukke opp her for å lagre en mer kompleks sparsom filstruktur (dessverre er jeg ikke kjent med alle detaljene om hvordan sparsomme filer fungerer).
  • Negativ (CPU), på grunn av behovet for å dekomprimere sider.
  • Det er ingen innvirkning på skriveoperasjoner.
  • Innvirkning på sjekkpunktprosessen (alt her ligner på leseoperasjoner):
  • Positiv (disk IO), på grunn av en reduksjon i antall skrevne filsystemblokker.
  • Negativ (CPU, muligens disk IO), på grunn av arbeid med sparsomme filer.
  • Negativ (CPU), på grunn av behovet for sidekomprimering.

Hvilken side av skalaen vil tippe skalaen? Alt dette avhenger veldig av miljøet, men jeg er tilbøyelig til å tro at komprimering av diskside mest sannsynlig vil føre til ytelsesforringelse på de fleste systemer. Dessuten viser tester på andre DBMS-er som bruker en lignende tilnærming med sparsomme filer et fall i ytelse når komprimering er aktivert.

Hvordan aktivere og konfigurere

Som nevnt ovenfor er minimumsversjonen av Apache Ignite som støtter disksidekomprimering 2.8 og kun Linux-operativsystemet støttes. Aktiver og konfigurer som følger:

  • Det må være en ignite-compression-modul i klassebanen. Som standard er den plassert i Apache Ignite-distribusjonen i libs/valgfri katalog og er ikke inkludert i klassebanen. Du kan ganske enkelt flytte katalogen opp ett nivå til libs, og når du kjører den gjennom ignite.sh blir den automatisk aktivert.
  • Persistens må være aktivert (aktivert via DataRegionConfiguration.setPersistenceEnabled(true)).
  • Sidestørrelsen må være større enn filsystemets blokkstørrelse (du kan angi den med DataStorageConfiguration.setPageSize() ).
  • For hver cache hvis data må komprimeres, må du konfigurere komprimeringsmetoden og (valgfritt) komprimeringsnivået (metoder) CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

WAL komprimering

Hvordan fungerer det

Hva er WAL og hvorfor er det nødvendig? Veldig kort: dette er en logg som inneholder alle hendelser som til slutt endrer sidelagringen. Det trengs først og fremst for å kunne komme seg ved fall. Enhver operasjon, før den gis kontroll til brukeren, må først registrere en hendelse i WAL, slik at den i tilfelle feil kan spilles av i loggen og gjenopprette alle operasjoner som brukeren har mottatt et vellykket svar på, selv om disse operasjonene rakk ikke å reflekteres i sidelagringen på disk (allerede ovenfor Det er beskrevet at selve skrivingen til sidelageret gjøres i en prosess som kalles "sjekkpunkt" med noe forsinkelse av separate tråder).

Oppføringer i WAL er delt inn i logiske og fysiske. Boolske er nøklene og verdiene selv. Fysisk – reflekterer endringer på sider i sidebutikken. Mens logiske poster kan være nyttige for noen andre tilfeller, er fysiske poster kun nødvendig for gjenoppretting i tilfelle krasj, og poster er kun nødvendig siden siste vellykkede sjekkpunkt. Her skal vi ikke gå i detalj og forklare hvorfor det fungerer slik, men interesserte kan henvise til den allerede nevnte artikkelen på Apache Ignite Wiki: Ignite Persistent Store - under panseret.

Det er ofte flere fysiske poster per logisk post. Det vil si at for eksempel en putoperasjon i cachen påvirker flere sider i sideminnet (en side med selve dataene, sider med indekser, sider med frilister). I noen syntetiske tester fant jeg at fysiske poster okkuperte opptil 90 % av WAL-filen. De er imidlertid nødvendige i svært kort tid (som standard er intervallet mellom sjekkpunkter 3 minutter). Det ville være logisk å kvitte seg med disse dataene etter å ha mistet relevansen. Dette er nøyaktig hva WAL-komprimeringsmekanismen gjør: den kvitter seg med fysiske poster og komprimerer de resterende logiske postene ved hjelp av zip, mens filstørrelsen reduseres veldig betydelig (noen ganger med titalls ganger).

Fysisk sett består WAL av flere segmenter (10 som standard) med fast størrelse (64 MB som standard), som overskrives på en sirkulær måte. Så snart det aktuelle segmentet er fylt, blir neste segment tilordnet som gjeldende, og det fylte segmentet kopieres til arkivet med en egen tråd. WAL-komprimering fungerer allerede med arkivsegmenter. Også, som en egen tråd, overvåker den utførelsen av sjekkpunktet og begynner komprimering i arkivsegmenter som fysiske poster ikke lenger er nødvendige for.

Datakomprimering i Apache Ignite. Sbers erfaring

Ytelsespåvirkning

Siden WAL-komprimering går som en egen tråd, bør det ikke være noen direkte innvirkning på operasjonene som utføres. Men det legger fortsatt ekstra bakgrunnsbelastning på CPU (komprimering) og disk (leser hvert WAL-segment fra arkivet og skriver de komprimerte segmentene), så hvis systemet kjører på maksimal kapasitet, vil det også føre til ytelsesforringelse.

Hvordan aktivere og konfigurere

Du kan aktivere WAL-komprimering ved å bruke egenskapen WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Ved å bruke DataStorageConfiguration.setWalCompactionLevel()-metoden kan du også angi komprimeringsnivået hvis du ikke er fornøyd med standardverdien (BEST_SPEED).

WAL-sides øyeblikksbildekomprimering

Hvordan fungerer det

Vi har allerede funnet ut at i WAL er poster delt inn i logiske og fysiske. For hver endring på hver side genereres en fysisk WAL-post i sideminnet. Fysiske poster er på sin side også delt inn i 2 undertyper: sidesnapshot record og delta record. Hver gang vi endrer noe på en side og overfører det fra en ren tilstand til en skitten tilstand, lagres en fullstendig kopi av denne siden i WAL (side snapshot record). Selv om vi bare endret én byte i WAL, vil posten være litt større enn sidestørrelsen. Hvis vi endrer noe på en allerede skitten side, dannes en delta-post i WAL, som kun gjenspeiler endringer sammenlignet med forrige tilstand på siden, men ikke hele siden. Siden tilbakestilling av sidens tilstand fra skitne til rene utføres under sjekkpunktprosessen, umiddelbart etter starten av sjekkpunktet, vil nesten alle fysiske poster kun bestå av øyeblikksbilder av sider (siden alle sider umiddelbart etter starten av sjekkpunktet er rene) , så når vi nærmer oss neste sjekkpunkt, begynner delta-postfraksjonen å vokse og tilbakestilles igjen ved begynnelsen av neste sjekkpunkt. Målinger i noen syntetiske tester viste at andelen sidebilder av det totale volumet av fysiske poster når 90 %.

Ideen med WAL-sidesnapshot-komprimering er å komprimere side-snapshots ved å bruke et ferdig sidekomprimeringsverktøy (se disksidekomprimering). Samtidig, i WAL, lagres poster sekvensielt i bare vedlegg-modus, og det er ikke nødvendig å binde poster til grensene for filsystemblokker, så her, i motsetning til disksidekomprimeringsmekanismen, trenger vi ikke sparsomme filer på alt; følgelig vil denne mekanismen ikke bare fungere på OS Linux. I tillegg spiller det ingen rolle for oss lenger hvor mye vi klarte å komprimere siden. Selv om vi frigjorde 1 byte, er dette allerede et positivt resultat, og vi kan lagre komprimerte data i WAL, i motsetning til disksidekomprimering, hvor vi lagrer den komprimerte siden bare hvis vi frigjorde mer enn 1 filsystemblokk.

Sider er svært komprimerbare data, deres andel av det totale WAL-volumet er veldig høy, så uten å endre WAL-filformatet kan vi få en betydelig reduksjon i størrelsen. Komprimering, inkludert logiske poster, vil kreve en endring i format og tap av kompatibilitet, for eksempel for eksterne forbrukere som kan være interessert i logiske poster, men vil ikke føre til en betydelig reduksjon i filstørrelse.

Som med disksidekomprimering, kan WAL-sides snapshot-komprimering bruke ZSTD, LZ4, Snappy-komprimeringsalgoritmer, samt SKIP_GARBAGE-modus.

Ytelsespåvirkning

Det er ikke vanskelig å legge merke til at direkte aktivering av WAL-sidesnapshot-komprimering bare påvirker tråder som skriver data til sideminnet, det vil si de trådene som endrer data i cacher. Lesing av fysiske poster fra WAL skjer kun én gang, i det øyeblikket noden heves etter et fall (og bare hvis den faller under et sjekkpunkt).

Dette påvirker tråder som endrer data på følgende måte: vi får en negativ effekt (CPU) på grunn av behovet for å komprimere siden hver gang før skriving til disk, og en positiv effekt (disk IO) på grunn av en reduksjon i mengden av data skrevet. Følgelig er alt enkelt her: hvis systemytelsen er begrenset av CPU, får vi en liten degradering, hvis den er begrenset av disk I/O, får vi en økning.

Indirekte påvirker reduksjon av WAL-størrelsen også (positivt) strømmer som dumper WAL-segmenter inn i arkiv- og WAL-komprimeringsstrømmene.

Virkelige ytelsestester i miljøet vårt ved bruk av syntetiske data viste en liten økning (gjennomstrømningen økte med 10%-15%, latensen redusert med 10%-15%).

Hvordan aktivere og konfigurere

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

  • Det må være en ignite-compression-modul i klassebanen. Som standard er den plassert i Apache Ignite-distribusjonen i libs/valgfri katalog og er ikke inkludert i klassebanen. Du kan ganske enkelt flytte katalogen opp ett nivå til libs, og når du kjører den gjennom ignite.sh blir den automatisk aktivert.
  • Persistens må være aktivert (aktivert via DataRegionConfiguration.setPersistenceEnabled(true)).
  • Komprimeringsmodusen må stilles inn ved hjelp av metoden DataStorageConfiguration.setWalPageCompression(), komprimering er deaktivert som standard (DISABLED-modus).
  • Eventuelt kan du angi komprimeringsnivået ved hjelp av metoden DataStorageConfiguration.setWalPageCompression(), se javadoc for metoden for gyldige verdier for hver modus.

Konklusjon

De vurderte datakomprimeringsmekanismene i Apache Ignite kan brukes uavhengig av hverandre, men enhver kombinasjon av dem er også akseptabel. Når du forstår hvordan de fungerer, kan du finne ut hvor egnet de er for oppgavene dine i miljøet ditt og hva du må ofre når du bruker dem. Disksidekomprimering er designet for å komprimere hovedlagringen og kan gi et middels komprimeringsforhold. WAL side snapshot komprimering vil gi en gjennomsnittlig grad av komprimering for WAL filer, og vil mest sannsynlig til og med forbedre ytelsen. WAL-komprimering vil ikke ha en positiv effekt på ytelsen, men vil redusere størrelsen på WAL-filer så mye som mulig ved å fjerne fysiske poster.

Kilde: www.habr.com

Legg til en kommentar