NÀr man arbetar med stora datamÀngder kan problemet med brist pÄ diskutrymme ibland bli akut. Ett av sÀtten att lösa detta problem Àr komprimering, vilket gör att man kan öka lagringskapaciteten pÄ samma hÄrdvara. I denna artikel kommer vi att titta pÄ hur datakomprimering fungerar i Apache Ignite. Endast de metoder som Àr implementerade i produkten för diskkomprimering kommer att behandlas. Andra metoder för datakomprimering (över nÀtverket, i minnet) bÄde de som Àr implementerade och de som inte Àr, kommer att hÄllas utanför ramen.
SÄ, nÀr persistenslÀget Àr aktiverat, börjar Ignite skriva till disken som ett resultat av Àndringar i cacharna:
- InnehÄllet i cacharna
- Förhandsgranskningslogg (Write Ahead Log, hÀr kallad WAL)
Det har funnits en mekanism för att komprimera WAL under en lÀngre tid, kÀnd som WAL-komprimering. I den nyligen slÀppta Apache Ignite 2.8 har tvÄ ytterligare mekanismer introducerats som gör det möjligt att komprimera data pÄ disken: disk sida komprimering för att komprimera innehÄllet i cacharna och WAL sida snapshot komprimering för att komprimera vissa poster i WAL. Mer information om dessa tre mekanismer finns nedan.
Disk sida komprimering
Hur det fungerar
För att börja med ska vi kort gÄ igenom hur Ignite lagrar data. För lagring anvÀnds sidminne. Sidstorleken sÀtts vid start av noden och kan inte Àndras senare, dessutom mÄste sidstorleken vara en potenti av tvÄ och vara ett multipel av storleken pÄ filsystemets block. Sidor laddas in i RAM frÄn disken vid behov, storleken pÄ data pÄ disken kan överskrida den tilldelade RAM-kapaciteten. Om det saknas utrymme i RAM för att ladda en sida frÄn disken kommer gamla, redan oanvÀnda sidor att trÀngas ut frÄn RAM.
PÄ disken lagras data pÄ följande sÀtt: för varje partition av varje cachegrupp skapas en separat fil, i denna fil kommer sidor att följas i ordning av stigande index. Det fullstÀndiga identifieringsnumret för en sida innehÄller identifieringsnumret för cachegruppen, partitionsnumret och sidans index i filen. PÄ sÄ sÀtt kan vi entydigt bestÀmma filen och offsetet i filen för varje sida utifrÄn det fullstÀndiga identifieringsnumret. För mer information om strukturen av sidminnet kan du lÀsa artikeln pÄ Apache Ignite Wiki: .
Disk page compression, som namnet antyder, fungerar pÄ sidor-nivÄ. NÀr denna mekanism Àr aktiverad, hanteras data i RAM som den Àr, utan nÄgon komprimering, men i ögonblicket dÄ sidor sparas frÄn RAM till disk, sker en komprimering av dem.
Men att komprimera varje sida individuellt löser fortfarande inte problemet, vi mÄste pÄ nÄgot sÀtt minska storleken pÄ de slutgiltiga filerna med data. Om storleken pÄ sidan slutar vara fast, kan vi inte lÀngre skriva sidor till fil en efter en, eftersom detta kan ge upphov till en rad problem:
- Vi kommer inte att kunna berÀkna offset för sidan i filen med hjÀlp av sidans index.
- Det Àr oklart vad vi ska göra med sidor som inte Àr i slutet av filen och som Àndrar sin storlek. Om storleken pÄ sidan minskar, försvinner utrymmet som den frigjorde. Om storleken pÄ sidan ökar, mÄste man leta efter en ny plats för den i filen.
- Om sidan flyttas ett antal byte som inte Àr delbart med filsystemets blockstorlek, kommer en extra block av filsystemet att beröras för att lÀsa eller skriva den, vilket kan leda till prestandaförsÀmring.
För att undvika att hantera dessa problem pÄ egen nivÄ, anvÀnder disk page compression i Apache Ignite en filsystemsmekanism kallad sparse filer. En sparse (sparse) fil Àr en fil dÀr vissa regioner, som fyllts med nollor, kan markeras som "hÄl". Inga filsystemblock kommer att allokeras för att lagra dessa hÄl, vilket resulterar i diskutrymmesbesparing.
Det Àr logiskt att för att frigöra ett filsystemblock mÄste storleken pÄ hÄlet vara större Àn eller lika med storleken pÄ filsystemets block, vilket lÀgger till en ytterligare begrÀnsning för sidstorleken i Apache Ignite: för att komprimeringen ska ha nÄgon effekt mÄste storleken pÄ sidan vara strikt större Àn storleken pÄ filsystemets block. Om storleken pÄ sidan Àr lika med storleken pÄ blocket, kan vi aldrig frigöra nÄgot block, eftersom för att frigöra ett enda block mÄste den komprimerade sidan ta upp 0 byte. Om storleken pÄ sidan dÀremot Àr lika med storleken pÄ 2 eller 4 block, kan vi frigöra minst ett block om vÄr sida komprimeras med minst 50% eller 75% respektive.
SÄledes Àr den slutliga beskrivningen av mekanismens arbete: NÀr en sida skrivs till disken görs ett försök att komprimera sidan. Om den komprimerade sidans storlek tillÄter att en eller flera block av filsystemet frigörs, skrivs sidan i komprimerad form, och pÄ platsen för de frigjorda blocken skapas en "hÄl" (ett systemanrop med flaggan "punch hole"). fallocate() Om den komprimerade sidans storlek inte tillÄter block att frigöras, sparas sidan som den Àr, i okomprimerad form. Alla sidoffsetar berÀknas pÄ samma sÀtt som utan kompression, genom att multiplicera sidans index med sidans storlek. Ingen omlokalisering av sidor krÀvs pÄ egen hand. Sidoffsetar, liksom utan kompression, hamnar vid grÀnserna för filsystemets block.

I den aktuella implementationen kan Ignite endast arbeta med sparsamma filer under Linux OS; dÀrmed kan disk sidkompression endast aktiveras vid anvÀndning av Ignite pÄ detta operativsystem.
Komprimeringsalgoritmer som kan anvÀndas för disk sidkompression: ZSTD, LZ4, Snappy. Dessutom finns det en driftlÀge (SKIP_GARBAGE), dÀr endast oanvÀnd plats pÄ sidan tas bort utan att kompression tillÀmpas pÄ de ÄterstÄende uppgifterna, vilket gör att CPU-belastningen minskar jÀmfört med de tidigare nÀmnda algoritmerna.
PÄverkan pÄ prestanda
TyvÀrr har jag inte gjort nÄgra faktiska prestandamÀtningar pÄ verkliga plattformar, eftersom vi inte planerar att anvÀnda denna mekanism i produktion, men vi kan teoretiskt diskutera var vi kommer att förlora och var vi kommer att vinna.
För detta behöver vi minnas hur lÀsning och skrivning av sidor utförs nÀr vi gör förfrÄgningar till dem:
- Vid lÀsoperationen söks sidan först i RAM. Om sökningen misslyckas, laddas sidan in i RAM frÄn disken av samma trÄd som gör lÀsningen.
- Vid skrivoperationen markeras sidan i RAM som smutsig, men den fysiska sparingen av sidan till disken sker inte direkt inom trÄden som utför skrivningen. Alla smutsiga sidor sparas till disken senare under checkpoint-processen av separata trÄdar.
SÄledes pÄverkas lÀsoperationer:
- Positivt (disk IO), genom att antalet lÀsta block av filsystemet minskar.
- Negativt (CPU) pÄ grund av den extra belastning som operativsystemet behöver för att hantera sparse-filer. Det kan ocksÄ finnas ytterligare IO-operationer för att bevara en mer komplex struktur av sparse-filer (jag Àr tyvÀrr inte bekant med alla detaljer kring hur sparse-filer fungerar).
- Negativt (CPU) pÄ grund av behovet av att dekomprimera sidor.
- Ingen pÄverkan pÄ skrivoperationer.
- PÄverkan pÄ checkpoint-processen (liknande lÀsoperationer):
- Positivt (disk IO) pÄ grund av minskningen av antalet skrivna block i filsystemet.
- Negativt (CPU, möjligtvis disk IO) pÄ grund av hantering av sparse-filer.
- Negativt (CPU) pÄ grund av behovet av att komprimera sidor.
Vilken skÄl vÀger tyngre? Detta beror vÀldigt mycket pÄ miljön, men jag lutar Ät att disk page compression snarare kommer att leda till prestandadegradering pÄ de flesta system. Dessutom visar tester pÄ andra databashanterare som anvÀnder liknande metoder med sparse-filer att prestandan minskar med aktiverad komprimering.
Hur man aktiverar och konfigurerar
Som nÀmnts tidigare Àr den minimi version av Apache Ignite som stöder disk page compression: 2.8 och stöds endast av operativsystemet Linux. Aktivering och konfiguration görs pÄ följande sÀtt:
- I class-path mÄste modulen ignite-compression finnas. Som standard ligger den i distributionspaketet av Apache Ignite i katalogen libs/optional och ingÄr inte i class-path. Du kan helt enkelt flytta katalogen en nivÄ upp i libs sÄ att den automatiskt inkluderas vid körning genom ignite.sh.
- Persistens mÄste vara aktiverat (aktiveras genom
DataRegionConfiguration.setPersistenceEnabled(true)). - Sidstorleken mÄste vara större Àn blockstorleken i filsystemet (detta kan stÀllas in med
DataStorageConfiguration.setPageSize()). - För varje cache vars data behöver komprimeras, mÄste komprimeringsmetod och (valfritt) komprimeringsnivÄ stÀllas in i konfigurationen (metoderna
CacheConfiguration.setDiskPageCompression(), CacheConfiguration.setDiskPageCompressionLevel()).
WAL-komprimering
Hur det fungerar
Vad Àr WAL och varför behövs det? Mycket kort: det Àr en logg dÀr alla hÀndelser som i slutÀndan förÀndrar sidlagringen registreras. Det behövs först och frÀmst för att kunna ÄterstÀlla vid ett fel. Varje operation mÄste först registrera en hÀndelse i WAL innan den ger kontrollen tillbaka till anvÀndaren, för att kunna Äterskapa alla operationer som anvÀndaren fick ett framgÄngsrikt svar pÄ, Àven om dessa operationer inte hann Äterspeglas i sidlagringen pÄ disken (det har tidigare beskrivits att den faktiska skrivningen till sidlagringen görs i en process som kallas "checkpoint" med viss fördröjning av separata trÄdar).
Posterna i WAL delas upp i logiska och fysiska. Logiska Àr sjÀlva nycklarna och vÀrdena. Fysiska reflekterar förÀndringar i sidorna i sidlagringen. Om logiska poster kan vara anvÀndbara för vissa andra situationer, sÄ behövs fysiska poster endast för att ÄterstÀlla vid ett fel och de poster som behövs Àr endast frÄn den senaste framgÄngsrika checkpointen. HÀr kommer vi inte att gÄ in pÄ detaljer och förklara varför det fungerar just sÄ, men de som Àr intresserade kan vÀnda sig till den redan nÀmnda artikeln pÄ Apache Ignite Wiki: .
En logisk post motsvarar ofta flera fysiska poster. Det vill sÀga, till exempel sÄ berör en put-operation i cachen flera sidor i den sidlagrade minnet (sidan med sjÀlva data, sidorna med index, sidorna med free-listor). I vissa syntetiska tester har jag funnit att de fysiska posterna upptog upp till 90% av storleken pÄ WAL-filen. Samtidigt behövs de bara under en kort tid (som standard Àr intervallet mellan checkpoints 3 minuter). Det skulle vara logiskt att bli av med dessa data efter att de har förlorat sin aktualitet. Det Àr precis vad mekanismen för WAL-komprimering gör, den rensar bort fysiska poster och komprimerar de ÄterstÄende logiska posterna med hjÀlp av zip, vilket resulterar i en betydande minskning av filens storlek (ibland upp till tio gÄnger).
WAL bestÄr fysiskt av flera segment (som standard 10) av fast storlek (som standard 64MB), som skrivs över pÄ ett cykliskt sÀtt. NÀr det aktuella segmentet Àr fullt tilldelas det nÀsta segmentet, och det fyllda segmentet kopieras till arkivet i en separat ström. WAL-komprimering fungerar redan med arkiverade segment. Det övervakar ocksÄ checkpoints i en separat ström och pÄbörjar komprimering av arkiverade segment dÀr fysiska poster inte lÀngre behövs.

PÄverkan pÄ prestanda
Eftersom WAL-komprimering körs i en separat trÄd ska det inte ha nÄgon direkt inverkan pÄ de pÄgÄende operationerna. Men det ger ÀndÄ en extra bakgrundsbelastning pÄ CPU:n (komprimering) och disken (lÀsning av varje WAL-segment frÄn arkivet och skrivning av komprimerade segment), sÄ om systemet arbetar pÄ grÀnsen av sina möjligheter kan det ocksÄ leda till en nedgÄng i prestanda.
Hur man aktiverar och konfigurerar
WAL-komprimering kan aktiveras med hjÀlp av egenskapen WalCompactionEnabled pÄ DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Dessutom kan man med metoden DataStorageConfiguration.setWalCompactionLevel() stÀlla in komprimeringsgraden om standardvÀrdet (BEST_SPEED) inte Àr tillfredsstÀllande.
WAL sidavsnitt komprimering
Hur det fungerar
Tidigare har vi redan klargjort att WAL-poster delas in i logiska och fysiska. För varje Ă€ndring av varje sida i sidminnet skapas en fysisk WAL-post. Fysiska poster delas ocksĂ„ in i tvĂ„ underkategorier: page snapshot record och delta record. Varje gĂ„ng vi Ă€ndrar nĂ„got pĂ„ en sida och överför den frĂ„n ett rent tillstĂ„nd till ett smutsigt, sparas en fullstĂ€ndig kopia av denna sida i WAL (page snapshot record â sid snapshot). Ăven om vi endast har Ă€ndrat en enda byte kommer en post som Ă€r nĂ„got större Ă€n storleken pĂ„ sidan att sparas i WAL. Om vi dĂ€remot Ă€ndrar nĂ„got pĂ„ en redan smutsig sida skapas en delta record i WAL, vilken endast Ă„terspeglar Ă€ndringarna i jĂ€mförelse med det föregĂ„ende tillstĂ„ndet för sidan, men inte hela sidan. Eftersom Ă„terstĂ€llningen av sidors status frĂ„n smutsigt till rent utförs under checkpoint-processen, kommer nĂ€stan alla fysiska poster omedelbart efter att checkpointen har pĂ„börjats att bestĂ„ av endast sid snapshots (eftersom alla sidor omedelbart efter att checkpointen har pĂ„börjats Ă€r rena), och sedan, i takt med att vi nĂ€rmar oss nĂ€sta checkpoint, börjar andelen delta records vĂ€xa och Ă„terstĂ€lls igen vid början av nĂ€sta checkpoint. MĂ€tningar frĂ„n vissa syntetiska tester visade att andelen sid snapshots i den totala mĂ€ngden fysiska poster nĂ„r upp till 90%.
IdĂ©n med WAL page snapshot kompression gĂ„r ut pĂ„ att komprimera sid snapshots med hjĂ€lp av ett redan existerande verktyg för komprimering av sidor (se disk page compression). Under tiden sparas WAL-poster sekventiellt i ett append-only-lĂ€ge och det finns inget behov av att binda poster till grĂ€nserna för filsystemets block, sĂ„ hĂ€r, till skillnad frĂ„n mekanismen för disk page compression, har vi inte lĂ€ngre nĂ„got behov av sparsamma filer, vilket innebĂ€r att denna mekanism Ă€ven fungerar pĂ„ operativsystem som inte Ă€r Linux. Dessutom spelar det ingen roll hur mycket vi lyckas komprimera sidan. Ăven om vi frigör 1 byte Ă€r det redan ett positivt resultat och vi kan lagra de komprimerade uppgifterna i WAL, till skillnad frĂ„n disk page compression, dĂ€r vi endast sparar en komprimerad sida om vi har frigjort mer Ă€n 1 block av filsystemet.
Sidor Àr lÀtt komprimerbara data, deras andel av den totala storleken pÄ WAL Àr mycket hög, sÄ genom att inte Àndra formatet pÄ WAL-filen kan vi uppnÄ en betydande minskning av dess storlek. Komprimering av logiska poster skulle krÀva en Àndring av formatet och förlust av kompatibilitet, till exempel för externa konsumenter som kan vara intresserade av logiska poster, utan att det skulle medföra en betydande minskning av filstorleken.
Precis som för diskpage-komprimering kan algoritmer som ZSTD, LZ4, Snappy och Àven SKIP_GARBAGE-lÀget anvÀndas för WAL page snapshot-komprimering.
PÄverkan pÄ prestanda
Som det Àr lÀtt att se, pÄverkar direkt aktiveringen av WAL page snapshot-komprimering endast de trÄdar som skriver data i sidminnet, det vill sÀga de trÄdar som Àndrar data i cacheminnen. LÀsning frÄn WAL fysiska poster sker endast en gÄng, vid uppstart av noden efter ett fel (och endast om ett fel intrÀffar under en checkpoint).
Det pÄverkar de trÄdar som Àndrar data pÄ följande sÀtt: vi fÄr en negativ effekt (CPU) pÄ grund av behovet av att komprimera sidan varje gÄng innan vi skriver till disk och en positiv effekt (disk IO) pÄ grund av minskning av mÀngden skrivna data. DÀrför Àr det enkelt: om systemets prestanda begrÀnsas av CPU fÄr vi en liten nedgÄng, om det Àr disk I/O fÄr vi en ökning.
Indirekt minskning av WAL-storleken pÄverkar ocksÄ (positivt) de trÄdar som arkiverar WAL-segment och de trÄdar som ansvarar för WAL-komprimering.
Riktiga prestandatester i vÄr miljö med syntetiska data visade en liten ökning (genomströmningen ökade med 10%-15%, latensen minskade med 10%-15%).
Hur man aktiverar och konfigurerar
Minimikrav för Apache Ignite: 2.8. Aktivering och konfiguration görs pÄ följande sÀtt:
- I class-path mÄste modulen ignite-compression finnas. Som standard ligger den i distributionspaketet av Apache Ignite i katalogen libs/optional och ingÄr inte i class-path. Du kan helt enkelt flytta katalogen en nivÄ upp i libs sÄ att den automatiskt inkluderas vid körning genom ignite.sh.
- Persistens mÄste vara aktiverat (aktiveras genom
DataRegionConfiguration.setPersistenceEnabled(true)). - KomprimeringslÀget mÄste specificeras med metoden
DataStorageConfiguration.setWalPageCompression(), komprimering Àr som standard avstÀngt (lÀge DISABLED). - Valfritt kan graden av komprimering specificeras med metoden
DataStorageConfiguration.setWalPageCompression(), se javadoc för metoden för tillÄtna vÀrden för varje lÀge.
Slutsats
De behandlade mekanismerna för datakompression i Apache Ignite kan anvÀndas oberoende av varandra, men alla deras kombinationer Àr ocksÄ tillÄtna. Att förstÄ principerna för deras funktion kommer att hjÀlpa dig att avgöra hur vÀl de passar dina uppgifter i din miljö och vad du eventuellt mÄste kompromissa med vid anvÀndning. Disk sidkompression Àr avsedd för att komprimera det primÀra lagret och kan ge en genomsnittlig kompressionsgrad. WAL sid snapshot-kompression kommer att ge en genomsnittlig kompressionsgrad för WAL-filer, och det Àr troligt att det till och med ökar prestandan. WAL-kompaktion kommer inte att pÄverka prestandan positivt, men kommer att maximera minskningen av storleken pÄ WAL-filer genom att ta bort fysiska poster.
KĂ€lla: habr.com
