Kompresija podataka u Apache Ignite. Sberovo iskustvo

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

Dakle, s omogućenim postojanim načinom rada, kao rezultat promjena podataka u predmemoriji, Ignite počinje pisati na disk:

  1. Sadržaj spremnika
  2. Dnevnik pisanja unaprijed (u daljnjem tekstu jednostavno WAL)

Već neko vrijeme postoji mehanizam za WAL kompresiju, koji se zove WAL kompresija. Nedavno izdani Apache Ignite 2.8 uveo je još dva mehanizma koji vam omogućuju kompresiju podataka na disku: kompresiju stranice diska za kompresiju sadržaja predmemorije i kompresiju snimke WAL stranice za komprimiranje nekih WAL unosa. Više detalja o sva tri ova mehanizma u nastavku.

Kompresija stranice diska

Kako ovo radi

Prvo, pogledajmo vrlo kratko kako Ignite pohranjuje podatke. Memorija stranice koristi se za pohranu. Veličina stranice postavljena je na početku čvora i ne može se mijenjati u kasnijim fazama; također, veličina stranice mora biti potencija broja dva i višekratnik veličine bloka datotečnog sustava. Stranice se po potrebi učitavaju u RAM s diska; veličina podataka na disku može premašiti količinu dodijeljenog 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 disk u sljedećem obliku: za svaku particiju svake grupe predmemorije stvara se zasebna datoteka; u ovoj se datoteci stranice pojavljuju jedna za drugom u rastućem redoslijedu indeksa. Identifikator cijele stranice sadrži identifikator grupe predmemorije, 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. Možete pročitati više o straničnoj memoriji u članku Apache Ignite Wiki: Ignite Persistent Store - ispod haube.

Mehanizam sažimanja stranice diska, kao što možete pogoditi iz naziva, radi na razini stranice. Kada je ovaj mehanizam uključen, podaci u RAM-u se obrađuju takvi kakvi jesu, bez kompresije, ali kada se stranice spremaju iz RAM-a na disk, one su komprimirane.

Ali sažimanje svake stranice zasebno nije rješenje problema; morate nekako smanjiti veličinu rezultirajućih podatkovnih datoteka. Ako veličina stranice više nije fiksna, više ne možemo pisati stranice u datoteku jednu za drugom, jer to može stvoriti niz problema:

  • Pomoću indeksa stranice nećemo moći izračunati pomak po kojem se ona nalazi u datoteci.
  • Nije jasno što učiniti sa stranicama koje nisu na kraju datoteke i mijenjaju svoju veličinu. Ako se veličina stranice smanji, prostor koji je oslobodila nestaje. Ako se veličina stranice poveća, trebate potražiti novo mjesto u datoteci za to.
  • Ako se stranica pomakne za broj bajtova koji nije višekratnik veličine bloka datotečnog sustava, tada će njeno čitanje ili pisanje zahtijevati dodirivanje još jednog bloka datotečnog sustava, što može dovesti do degradacije performansi.

Kako bi se izbjeglo rješavanje ovih problema na vlastitoj razini, kompresija diskovne stranice u Apache Igniteu koristi mehanizam datotečnog sustava koji se naziva rijetke datoteke. Rijetka datoteka je ona u kojoj se neka područja ispunjena nulama mogu označiti kao "rupe". U tom slučaju neće biti dodijeljeni blokovi datotečnog sustava za pohranu ovih rupa, što će rezultirati uštedom prostora na disku.

Logično je da za oslobađanje bloka datotečnog sustava veličina rupe mora biti veća ili jednaka bloku datotečnog sustava, što nameće dodatna ograničenja na veličinu stranice i Apache Ignite: da bi kompresija imala ikakav učinak, veličina stranice mora biti strogo veća od veličine bloka datotečnog sustava. Ako je veličina stranice jednaka veličini bloka, tada nikada nećemo moći osloboditi niti jedan blok, jer da bi se oslobodio jedan blok, komprimirana stranica mora zauzimati 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 radi: Prilikom pisanja stranice na disk, pokušava se komprimirati stranica. Ako veličina komprimirane stranice dopušta oslobađanje jednog ili više blokova datotečnog sustava, tada se stranica piše u komprimiranom obliku, a na mjestu oslobođenih blokova pravi se "rupa" (izvršava se poziv sustava fallocate() sa zastavicom za bušenje rupa). Ako veličina komprimirane stranice ne dopušta oslobađanje blokova, stranica se sprema kakva jest, nekomprimirana. Svi pomaci stranice izračunavaju se na isti način kao i bez kompresije, množenjem indeksa stranice s veličinom stranice. Nije potrebno samostalno premještanje stranica. Pomaci stranice, baš kao i bez kompresije, padaju na granice blokova datotečnog sustava.

Kompresija podataka u Apache Ignite. Sberovo iskustvo

U trenutnoj implementaciji, Ignite može raditi samo s rijetkim datotekama pod Linux OS-om; sukladno tome, kompresija diskovne stranice može biti omogućena samo kada se Ignite koristi na ovom operativnom sustavu.

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

Utjecaj na izvedbu

Nažalost, nisam proveo stvarna mjerenja performansi na stvarnim tribinama, jer ne planiramo koristiti ovaj mehanizam u proizvodnji, ali možemo teoretski nagađati gdje ćemo izgubiti, a gdje dobiti.

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 traži u RAM-u; ako je pretraživanje neuspješno, stranica se učitava u RAM s diska od strane iste niti koja izvodi čitanje.
  • Kada se izvrši operacija pisanja, stranica u RAM-u je označena kao prljava, ali stranica nije odmah fizički spremljena na disk pomoću niti koja izvodi pisanje. Sve prljave stranice spremaju se na disk kasnije u procesu kontrolne točke u zasebnim nitima.

Dakle, utjecaj na operacije čitanja je:

  • Pozitivno (IO diska), zbog smanjenja broja čitanih blokova datotečnog sustava.
  • Negativno (CPU), zbog dodatnog opterećenja potrebnog operativnom sustavu za rad s rijetkim datotekama. Također je moguće da će se dodatne IO operacije implicitno pojaviti ovdje za spremanje složenije strukture rijetke datoteke (nažalost, nisam upoznat sa svim pojedinostima o tome kako rade rijetke datoteke).
  • Negativno (CPU), zbog potrebe dekompresije stranica.
  • Nema utjecaja na operacije pisanja.
  • Utjecaj na proces kontrolne točke (ovdje je sve slično operacijama čitanja):
  • Pozitivno (IO diska), zbog smanjenja broja zapisanih blokova datotečnog sustava.
  • Negativno (CPU, eventualno disk IO), zbog rada s rijetkim datotekama.
  • Negativno (CPU), zbog potrebe za kompresijom stranice.

Koja će strana vage prevrnuti vagu? Sve to uvelike ovisi o okruženju, ali sklon sam vjerovati da će kompresija diskovne stranice najvjerojatnije dovesti do degradacije performansi na većini sustava. Štoviše, testovi na drugim DBMS-ovima koji koriste sličan pristup s 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 diskovne stranice je 2.8 i podržan je samo operativni sustav Linux. Omogućite i konfigurirajte na sljedeći način:

  • Mora postojati modul ignite-compression u stazi klase. Prema zadanim postavkama nalazi se u distribuciji Apache Ignite u direktoriju libs/optional i nije uključen u stazu klase. Možete jednostavno premjestiti direktorij jednu razinu gore u libs i onda kada ga pokrenete kroz ignite.sh bit će automatski omogućen.
  • Postojanost mora biti omogućena (Omogućeno putem DataRegionConfiguration.setPersistenceEnabled(true)).
  • Veličina stranice mora biti veća od veličine bloka datotečnog sustava (možete je postaviti pomoću DataStorageConfiguration.setPageSize() ).
  • Za svaku predmemoriju čiji podaci trebaju biti komprimirani, morate konfigurirati metodu kompresije i (po izboru) razinu kompresije (metode CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

WAL zbijanje

Kako ovo radi

Što je WAL i zašto je potreban? Vrlo ukratko: ovo je dnevnik koji sadrži sve događaje koji u konačnici mijenjaju pohranu stranice. Potreban je prije svega za oporavak 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 kvara 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 u pohrani stranice na disku (već je gore opisano da se stvarno pisanje u pohranu stranice vrši u procesu koji se naziva "kontrolne točke" s određenim kašnjenjem zasebnih niti).

Unosi u WAL-u dijele se na logičke i fizičke. Booleovi su sami ključevi i vrijednosti. Fizički - odražava promjene na stranicama u trgovini 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 zadnje uspješne kontrolne točke. Ovdje nećemo ići u detalje i objašnjavati zašto to tako funkcionira, 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 predmemoriju utječe na nekoliko stranica u memoriji stranica (stranicu sa samim podacima, stranice s indeksima, stranice s besplatnim listama). U nekim sintetičkim testovima otkrio sam da fizički zapisi zauzimaju do 90% WAL datoteke. Međutim, oni su potrebni vrlo kratko (prema zadanim postavkama, interval između kontrolnih točaka je 3 minute). Bilo bi logično riješiti se ovih podataka nakon što su izgubili svoju relevantnost. Upravo to radi mehanizam sažimanja WAL-a: rješava se fizičkih zapisa i komprimira preostale logičke zapise pomoću zip-a, dok se veličina datoteke vrlo značajno smanjuje (ponekad i desetke puta).

Fizički, WAL se sastoji od nekoliko segmenata (10 prema zadanim postavkama) fiksne veličine (64 MB prema zadanim postavkama), koji se kružno prepisuju. Čim se trenutni segment popuni, sljedeći segment se dodjeljuje kao trenutni, a ispunjeni segment se kopira u arhivu zasebnom niti. WAL sažimanje već radi sa segmentima arhive. Također, kao zasebna nit, prati izvođenje kontrolne točke i započinje kompresiju u segmentima arhive za koje fizički zapisi više nisu potrebni.

Kompresija podataka u Apache Ignite. Sberovo iskustvo

Utjecaj na izvedbu

Budući da se WAL sažimanje izvodi kao zasebna nit, ne bi trebalo biti izravnog utjecaja na operacije koje se izvode. Ali još uvijek stavlja dodatno pozadinsko opterećenje na CPU (kompresija) i disk (čitanje svakog WAL segmenta iz arhive i pisanje komprimiranih segmenata), tako da ako sustav radi na svom maksimalnom kapacitetu, to će također dovesti do degradacije performansi.

Kako omogućiti i konfigurirati

Pomoću svojstva možete omogućiti WAL sažimanje WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Također, pomoću metode DataStorageConfiguration.setWalCompactionLevel() možete postaviti razinu kompresije ako niste zadovoljni zadanom vrijednošću (BEST_SPEED).

WAL kompresija snimke stranice

Kako ovo radi

Već smo saznali da se u WAL-u zapisi dijele na logičke i fizičke. Za svaku promjenu svake stranice, fizički WAL zapis se generira u memoriji stranice. Fizički zapisi se također dijele u 2 podvrste: zapis snimke stranice i delta zapis. Svaki put kada nešto promijenimo na stranici i prebacimo je iz čistog u prljavo stanje, potpuna kopija te stranice pohranjuje se u WAL (page snapshot record). Čak i ako smo promijenili samo jedan bajt u WAL-u, zapis će biti malo veći od veličine stranice. Ako promijenimo nešto 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 iz prljavog u čisto izvodi tijekom procesa kontrolne točke, odmah nakon početka kontrolne točke, gotovo svi fizički zapisi sastojat će se samo od snimki stranica (budući da su sve stranice odmah nakon početka kontrolne točke čiste) , zatim kako se približavamo sljedećoj kontrolnoj točki, udio delta zapisa počinje rasti i ponovno se poništava na početku sljedeće kontrolne točke. Mjerenja u nekim sintetičkim testovima pokazala su da udio snimki stranica u ukupnom volumenu fizičkih zapisa doseže 90%.

Ideja WAL kompresije snimki stranica je komprimirati snimke stranica pomoću gotovog alata za kompresiju stranica (pogledajte kompresiju stranice na disku). U isto vrijeme, u WAL-u, zapisi se spremaju sekvencijalno u načinu samo dodavanja i nema potrebe vezati zapise za granice blokova datotečnog sustava, tako da ovdje, za razliku od mehanizma kompresije stranice diska, ne trebamo rijetke datoteke na sve; prema 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, to je već pozitivan rezultat i možemo spremiti komprimirane podatke u WAL, za razliku od kompresije stranice diska, gdje spremamo komprimiranu stranicu samo ako smo oslobodili više od 1 bloka datotečnog sustava.

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

Kao i kod kompresije diskovne stranice, kompresija snimke WAL stranice može koristiti algoritme kompresije ZSTD, LZ4, Snappy, kao i način rada SKIP_GARBAGE.

Utjecaj na izvedbu

Nije teško uočiti da izravno uključivanje WAL kompresije snimke stranice utječe samo na niti koje zapisuju podatke u memoriju stranice, odnosno one niti koje mijenjaju podatke u predmemoriji. Čitanje fizičkih zapisa iz WAL-a događa se samo jednom, u trenutku kada se čvor podigne nakon pada (i samo ako padne tijekom kontrolne točke).

To utječe na niti koje mijenjaju podatke na sljedeći način: dobivamo negativan učinak (CPU) zbog potrebe za komprimiranjem stranice svaki put prije pisanja na disk i pozitivan učinak (IO diska) zbog smanjenja količine podaci napisani. U skladu s tim, ovdje je sve jednostavno: ako je rad sustava ograničen CPU-om, dobivamo blagu degradaciju, ako je ograničen I/O-om diska, dobivamo povećanje.

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

Stvarni testovi performansi u našem okruženju korištenjem sintetičkih podataka pokazali su blagi porast (propusnost povećana za 10%-15%, latencija smanjena za 10%-15%).

Kako omogućiti i konfigurirati

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

  • Mora postojati modul ignite-compression u stazi klase. Prema zadanim postavkama nalazi se u distribuciji Apache Ignite u direktoriju libs/optional i nije uključen u stazu klase. Možete jednostavno premjestiti direktorij jednu razinu gore u libs i onda kada ga pokrenete kroz ignite.sh bit će automatski omogućen.
  • Postojanost mora biti omogućena (Omogućeno putem DataRegionConfiguration.setPersistenceEnabled(true)).
  • Način kompresije mora se postaviti pomoću metode DataStorageConfiguration.setWalPageCompression(), kompresija je onemogućena prema zadanim postavkama (DISABLED mode).
  • Po želji, možete postaviti razinu kompresije pomoću metode DataStorageConfiguration.setWalPageCompression(), pogledajte javadoc za metodu za važeće vrijednosti za svaki način.

Zaključak

Razmatrani mehanizmi kompresije podataka u Apache Igniteu mogu se koristiti neovisno jedan o drugom, ali je prihvatljiva i svaka njihova kombinacija. Razumijevanje načina na koji rade omogućit će vam da odredite koliko su prikladni za vaše zadatke u vašem okruženju i što ćete morati žrtvovati kada ih koristite. Kompresija diskovne stranice dizajnirana je za komprimiranje glavne pohrane i može dati srednji omjer kompresije. Kompresija snimke WAL stranice dat će prosječan stupanj kompresije za WAL datoteke i najvjerojatnije će čak poboljšati performanse. WAL sažimanje 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