Kompresija podataka u Apache Ignite. Sberovo iskustvo

Kompresija podataka u Apache Ignite. Sberovo iskustvoKada radite sa velikim količinama podataka, ponekad se može pojaviti problem nedostatka prostora na disku. Jedan od načina za rješavanje ovog problema je kompresija, zahvaljujući kojoj, na istoj opremi, možete sebi priuštiti povećanje volumena pohrane. U ovom članku ćemo pogledati kako funkcionira kompresija podataka u Apache Ignite-u. Ovaj članak će opisati samo metode kompresije diska implementirane u proizvodu. Ostale metode kompresije podataka (preko mreže, u memoriji), bez obzira da li su implementirane ili ne, ostat će izvan opsega.

Dakle, s uključenim režimom postojanosti, kao rezultat promjena u podacima u keš memoriji, Ignite počinje pisati na disk:

  1. Sadržaj keša
  2. Write Ahead Log (u daljem tekstu jednostavno WAL)

Već neko vrijeme postoji mehanizam za WAL kompresiju, koji se zove WAL sabijanje. Nedavno objavljeni Apache Ignite 2.8 uveo je još dva mehanizma koji vam omogućavaju da komprimirate podatke na disku: kompresiju stranice diska za kompresiju sadržaja keš memorije i kompresiju snimka WAL stranice za komprimiranje nekih WAL unosa. Više detalja o sva tri ova mehanizma u nastavku.

Kompresija stranice na disku

Kako ovo radi

Prvo, pogledajmo vrlo kratko kako Ignite pohranjuje podatke. Memorija stranica se koristi za skladištenje. Veličina stranice je postavljena na početku čvora i ne može se mijenjati u kasnijim fazama; također, veličina stranice mora biti stepen dva i višestruka veličina bloka sistema datoteka. Stranice se učitavaju u RAM sa diska po potrebi; veličina podataka na disku može premašiti količinu dodijeljene RAM-a. Ako u RAM-u nema dovoljno prostora za učitavanje stranice s diska, stare stranice koje se više ne koriste bit će izbačene iz RAM-a.

Podaci se pohranjuju na disku u sljedećem obliku: za svaku particiju svake grupe keša kreira se posebna datoteka; u ovoj datoteci stranice se pojavljuju jedna za drugom u rastućem indeksnom redoslijedu. Identifikator cijele stranice sadrži identifikator grupe keš memorije, broj particije i indeks stranice u datoteci. Dakle, koristeći identifikator cijele stranice, možemo jedinstveno odrediti datoteku i pomak u datoteci za svaku stranicu. Više o paging memoriji možete pročitati u članku Apache Ignite Wiki: Ignite Persistent Store - ispod haube.

Mehanizam kompresije stranice na disku, kao što možete pretpostaviti iz imena, radi na nivou stranice. Kada je ovaj mehanizam omogućen, podaci u RAM-u se obrađuju takvi kakvi jesu, bez ikakve kompresije, ali kada se stranice pohranjuju iz RAM-a na disk, one se komprimiraju.

Ali komprimiranje svake stranice pojedinačno nije rješenje problema; morate nekako smanjiti veličinu rezultirajućih datoteka s podacima. Ako veličina stranice više nije fiksna, više ne možemo pisati stranice u fajl jednu za drugom, jer to može stvoriti niz problema:

  • Koristeći indeks stranice, nećemo moći izračunati pomak po kojem se nalazi u datoteci.
  • Nije jasno šta učiniti sa stranicama koje nisu na kraju datoteke i promijeniti njihovu veličinu. Ako se veličina stranice smanji, prostor koji je oslobodio nestaje. Ako se veličina stranice poveća, morate potražiti novo mjesto u datoteci za nju.
  • Ako se stranica pomiče za broj bajtova koji nije višekratnik veličine bloka sistema datoteka, tada će za čitanje ili pisanje zahtijevati dodirivanje još jednog bloka sistema datoteka, što može dovesti do degradacije performansi.

Da bi se izbjeglo rješavanje ovih problema na vlastitom nivou, kompresija stranice diska u Apache Ignite-u koristi mehanizam sistema datoteka koji se zove rijetke datoteke. Rijetka datoteka je ona u kojoj se neke regije popunjene nulom mogu označiti kao "rupe". U ovom slučaju, blokovi sistema datoteka neće biti dodijeljeni za pohranjivanje ovih rupa, što rezultira uštedom prostora na disku.

Logično je da da bi se oslobodio blok sistema datoteka, veličina rupe mora biti veća ili jednaka bloku sistema datoteka, što nameće dodatno ograničenje na veličinu stranice i Apache Ignite: da bi kompresija imala bilo kakav učinak, veličina stranice mora biti striktno veća od veličine bloka sistema datoteka. Ako je veličina stranice jednaka veličini bloka, tada nikada nećemo moći osloboditi jedan blok, jer da bi se oslobodio jedan blok, komprimirana stranica mora zauzeti 0 bajtova. Ako je veličina stranice jednaka veličini 2 ili 4 bloka, već ćemo moći osloboditi barem jedan blok ako je naša stranica komprimirana na najmanje 50% odnosno 75%.

Dakle, konačni opis kako mehanizam funkcionira: Prilikom pisanja stranice na disk, pokušava se komprimirati stranica. Ako veličina komprimirane stranice dozvoljava oslobađanje jednog ili više blokova sistema datoteka, tada se stranica piše u komprimiranom obliku, a umjesto oslobođenih blokova se pravi “rupa” (izvršava se sistemski poziv fallocate() sa zastavicom za bušenje). Ako veličina komprimirane stranice ne dozvoljava da se blokovi oslobode, stranica se pohranjuje kakva jest, nekomprimovana. Svi pomaci stranice se izračunavaju na isti način kao i bez kompresije, množenjem indeksa stranice sa veličinom stranice. Nije potrebno samostalno premještanje stranica. Pomaci stranica, baš kao i bez kompresije, padaju na granice blokova sistema datoteka.

Kompresija podataka u Apache Ignite. Sberovo iskustvo

U trenutnoj implementaciji, Ignite može raditi samo sa rijetkim datotekama pod Linux OS-om; u skladu s tim, kompresija stranice diska može biti omogućena samo kada se koristi Ignite na ovom operativnom sistemu.

Algoritmi kompresije koji se mogu koristiti za kompresiju stranica na disku: ZSTD, LZ4, Snappy. Osim toga, postoji način rada (SKIP_GARBAGE), u kojem se samo neiskorišteni prostor na stranici izbacuje bez primjene kompresije na preostale podatke, što smanjuje opterećenje CPU-a u odnosu na prethodno navedene algoritme.

Performance Impact

Nažalost, nisam izvršio stvarna mjerenja performansi na stvarnim tribinama, jer ne planiramo koristiti ovaj mehanizam u proizvodnji, ali teoretski možemo spekulirati gdje ćemo izgubiti, a gdje pobijediti.

Da bismo to učinili, moramo zapamtiti kako se stranice čitaju i pišu kada im se pristupa:

  • Prilikom izvođenja operacije čitanja, prvo se pretražuje u RAM-u; ako je pretraga neuspješna, stranica se učitava u RAM s diska od strane iste niti koja obavlja čitanje.
  • Kada se izvrši operacija pisanja, stranica u RAM-u je označena kao prljava, ali stranica nije fizički pohranjena na disk odmah od strane niti koja izvodi upis. Sve prljave stranice se spremaju na disk kasnije u procesu kontrolne tačke u odvojenim nitima.

Dakle, uticaj na operacije čitanja je:

  • Pozitivno (DISK IO), zbog smanjenja broja čitanih blokova sistema datoteka.
  • Negativno (CPU), zbog dodatnog opterećenja potrebnog operativnom sistemu za rad sa rijetkim datotekama. Također je moguće da će se dodatne IO operacije implicitno pojaviti ovdje kako bi se sačuvala složenija struktura rijetke datoteke (nažalost, nisam upoznat sa svim detaljima o tome kako rijetki fajlovi funkcionišu).
  • Negativno (CPU), zbog potrebe za dekompresijom stranica.
  • Nema uticaja na operacije pisanja.
  • Utjecaj na proces kontrolne točke (ovdje je sve slično operacijama čitanja):
  • Pozitivno (DISK IO), zbog smanjenja broja upisanih blokova sistema datoteka.
  • Negativno (CPU, eventualno disk IO), zbog rada sa rijetkim datotekama.
  • Negativno (CPU), zbog potrebe za kompresijom stranice.

Koja strana vage će preokrenuti vagu? Sve ovo u velikoj meri zavisi od okruženja, ali sam sklon da verujem da će kompresija stranice na disku najverovatnije dovesti do degradacije performansi na većini sistema. Štaviše, testovi na drugim DBMS-ovima koji koriste sličan pristup sa rijetkim datotekama pokazuju pad performansi kada je kompresija omogućena.

Kako omogućiti i konfigurirati

Kao što je gore spomenuto, minimalna verzija Apache Ignite-a koja podržava kompresiju stranica na disku je 2.8 i podržan je samo Linux operativni sistem. Omogućite i konfigurirajte na sljedeći način:

  • Mora postojati modul kompresije paljenja u stazi klase. Podrazumevano, nalazi se u Apache Ignite distribuciji u libs/optional direktorijumu i nije uključen u stazu klase. Možete jednostavno premjestiti direktorij za jedan nivo gore u libs i onda kada ga pokrenete kroz ignite.sh on će biti automatski omogućen.
  • Postojanost mora biti omogućena (Omogućeno preko DataRegionConfiguration.setPersistenceEnabled(true)).
  • Veličina stranice mora biti veća od veličine bloka sistema datoteka (možete je postaviti pomoću DataStorageConfiguration.setPageSize() ).
  • Za svaku keš memoriju čije podatke treba komprimirati, morate konfigurirati način kompresije i (opcionalno) nivo kompresije (metode CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

WAL sabijanje

Kako ovo radi

Šta je WAL i zašto je potreban? Vrlo kratko: ovo je dnevnik koji sadrži sve događaje koji na kraju mijenjaju pohranu stranice. Potreban je prvenstveno da bi se mogao oporaviti u slučaju pada. Svaka operacija prije davanja kontrole korisniku mora prvo zabilježiti događaj u WAL-u, tako da se u slučaju neuspjeha može reproducirati u dnevniku i vratiti sve operacije za koje je korisnik dobio uspješan odgovor, čak i ako su te operacije nije imao vremena da se odrazi na pohranjivanje stranica na disku (već gore je opisano da se stvarno upisivanje u skladište stranica vrši u procesu koji se zove "checkpointing" sa određenim kašnjenjem od strane odvojenih niti).

Unosi u WAL-u se dijele na logičke i fizičke. Booleovci su sami ključevi i vrijednosti. Fizički - odražava promjene na stranicama u prodavnici stranica. Dok logički zapisi mogu biti korisni u nekim drugim slučajevima, fizički zapisi su potrebni samo za oporavak u slučaju pada, a zapisi su potrebni samo od posljednje uspješne kontrolne tačke. Ovdje nećemo ulaziti u detalje i objašnjavati zašto to funkcionira na ovaj način, ali zainteresirani mogu pogledati već spomenuti članak na Apache Ignite Wiki: Ignite Persistent Store - ispod haube.

Često postoji nekoliko fizičkih zapisa po logičkom zapisu. To jest, na primjer, jedna operacija stavljanja u keš utiče na nekoliko stranica u memoriji stranica (stranica sa samim podacima, stranice sa indeksima, stranice sa slobodnim listama). U nekim sintetičkim testovima otkrio sam da fizički zapisi zauzimaju do 90% WAL datoteke. Međutim, oni su potrebni za vrlo kratko vrijeme (podrazumevano, interval između kontrolnih tačaka je 3 minute). Bilo bi logično da se riješite ovih podataka nakon što izgube relevantnost. Upravo to radi mehanizam za sabijanje WAL-a: oslobađa se fizičkih zapisa i komprimuje preostale logičke zapise pomoću zip-a, dok se veličina datoteke veoma značajno smanjuje (ponekad i desetinama puta).

Fizički, WAL se sastoji od nekoliko segmenata (10 po defaultu) fiksne veličine (64MB po defaultu), koji se kružno prepisuju. Čim se trenutni segment popuni, sljedeći segment se dodjeljuje kao tekući, a popunjeni segment se kopira u arhivu posebnom niti. WAL sabijanje već radi sa segmentima arhive. Također, kao zasebna nit, prati izvršavanje kontrolne tačke i započinje kompresiju u segmentima arhive za koje fizički zapisi više nisu potrebni.

Kompresija podataka u Apache Ignite. Sberovo iskustvo

Performance Impact

Budući da WAL sabijanje radi kao zasebna nit, ne bi trebalo biti direktnog utjecaja na operacije koje se izvode. Ali i dalje dodatno opterećuje CPU (kompresija) i disk (čitanje svakog WAL segmenta iz arhive i pisanje komprimovanih segmenata), tako da ako sistem radi na svom maksimalnom kapacitetu, to će takođe dovesti do degradacije performansi.

Kako omogućiti i konfigurirati

Možete omogućiti WAL sabijanje koristeći svojstvo WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Također, koristeći metodu DataStorageConfiguration.setWalCompactionLevel(), možete postaviti nivo kompresije ako niste zadovoljni zadanom vrijednošću (BEST_SPEED).

Kompresija snimka WAL stranice

Kako ovo radi

Već smo saznali da se u WAL zapisima dijele na logičke i fizičke. Za svaku promjenu svake stranice, fizički WAL zapis se generira u memoriji stranice. Fizički zapisi su takođe podijeljeni u 2 podvrste: zapis snimka stranice i delta zapis. Svaki put kada nešto promijenimo na stranici i prebacimo je iz čistog u prljavo stanje, potpuna kopija ove stranice se pohranjuje u WAL (snimak snimka stranice). Čak i ako promijenimo samo jedan bajt u WAL-u, zapis će biti nešto veći od veličine stranice. Ako nešto promijenimo na već prljavoj stranici, u WAL-u se formira delta zapis koji odražava samo promjene u odnosu na prethodno stanje stranice, ali ne i cijelu stranicu. Budući da se resetiranje stanja stranica sa prljavih na čiste vrši tokom procesa kontrolne tačke, odmah nakon početka kontrolne tačke, skoro svi fizički zapisi će se sastojati samo od snimaka stranica (pošto su sve stranice odmah nakon početka kontrolne tačke čiste) , tada kako se približavamo sljedećoj kontrolnoj tački, ulomak delta zapisa počinje da raste i ponovo se resetuje na početku sljedeće kontrolne tačke. Mjerenja u nekim sintetičkim testovima pokazala su da udio snimaka stranica u ukupnom obimu fizičkih zapisa dostiže 90%.

Ideja kompresije WAL snimaka stranica je komprimiranje snimaka stranica pomoću gotovog alata za kompresiju stranice (pogledajte kompresiju stranice na disku). Istovremeno, u WAL-u, zapisi se spremaju sekvencijalno u načinu samo dodavanja i nema potrebe da se zapisi vezuju za granice blokova sistema datoteka, tako da ovdje, za razliku od mehanizma kompresije stranice na disku, ne trebaju nam rijetke datoteke na sve; shodno tome, ovaj mehanizam neće raditi samo na OS Linux. Osim toga, više nam nije važno koliko smo uspjeli komprimirati stranicu. Čak i ako smo oslobodili 1 bajt, ovo je već pozitivan rezultat i možemo sačuvati komprimirane podatke u WAL-u, za razliku od kompresije stranice na disku, gdje čuvamo komprimiranu stranicu samo ako smo oslobodili više od 1 bloka sistema datoteka.

Stranice su vrlo kompresibilni podaci, njihov udio u ukupnom WAL volumenu je vrlo visok, tako da bez promjene WAL formata datoteke možemo postići značajno smanjenje njegove veličine. Kompresija, uključujući logičke zapise, zahtijevala bi promjenu formata i gubitak kompatibilnosti, na primjer, za eksterne korisnike koji bi mogli biti zainteresirani za logičke zapise, ali ne bi dovelo do značajnog smanjenja veličine datoteke.

Kao i kod kompresije disk stranice, WAL kompresija snimaka stranice može koristiti ZSTD, LZ4, Snappy algoritme kompresije, kao i SKIP_GARBAGE mod.

Performance Impact

Nije teško primijetiti da direktno omogućavanje WAL kompresije snimka stranice utiče samo na niti koje upisuju podatke u memoriju stranice, odnosno na one koje mijenjaju podatke u keš memoriji. Čitanje fizičkih zapisa iz WAL-a se dešava samo jednom, u trenutku kada se čvor podigne nakon pada (i samo ako padne tokom kontrolne tačke).

Ovo utiče na niti koje menjaju podatke na sledeći način: dobijamo negativan efekat (CPU) zbog potrebe da svaki put kompresujemo stranicu pre upisivanja na disk, i pozitivan efekat (disk IO) zbog smanjenja količine napisani podaci. U skladu s tim, ovdje je sve jednostavno: ako je performanse sistema ograničena CPU-om, dobijamo blagu degradaciju, ako je ograničena disk I/O, dobijamo povećanje.

Indirektno, smanjenje veličine WAL-a također utiče (pozitivno) na tokove koji izbacuju WAL segmente u arhivu i tokove sažimanja WAL-a.

Testovi stvarnih performansi u našem okruženju koristeći sintetičke podatke pokazali su blagi porast (propusnost je povećana za 10%-15%, latencija je smanjena za 10%-15%).

Kako omogućiti i konfigurirati

Minimalna verzija Apache Ignite: 2.8. Omogućite i konfigurirajte na sljedeći način:

  • Mora postojati modul kompresije paljenja u stazi klase. Podrazumevano, nalazi se u Apache Ignite distribuciji u libs/optional direktorijumu i nije uključen u stazu klase. Možete jednostavno premjestiti direktorij za jedan nivo gore u libs i onda kada ga pokrenete kroz ignite.sh on će biti automatski omogućen.
  • Postojanost mora biti omogućena (Omogućeno preko DataRegionConfiguration.setPersistenceEnabled(true)).
  • Način kompresije se mora postaviti pomoću metode DataStorageConfiguration.setWalPageCompression(), kompresija je onemogućena prema zadanim postavkama (DISABLED mode).
  • Opciono, možete postaviti nivo kompresije koristeći metodu DataStorageConfiguration.setWalPageCompression(), pogledajte javadoc za metodu za važeće vrijednosti za svaki način rada.

zaključak

Razmatrani mehanizmi kompresije podataka u Apache Ignite-u mogu se koristiti nezavisno jedan od drugog, ali je prihvatljiva i svaka njihova kombinacija. Razumijevanje načina na koji funkcioniraju omogućit će vam da odredite koliko su prikladni za vaše zadatke u vašem okruženju i šta ćete morati žrtvovati kada ih koristite. Kompresija stranica na disku je dizajnirana za komprimiranje glavne memorije i može dati srednji omjer kompresije. Kompresija snimka WAL stranice će dati prosječan stepen kompresije za WAL datoteke, a najvjerovatnije će čak i poboljšati performanse. Zbijanje WAL-a neće imati pozitivan učinak na performanse, ali će smanjiti veličinu WAL datoteka što je više moguće uklanjanjem fizičkih zapisa.

izvor: www.habr.com

Dodajte komentar