Komprimiranje podataka u Apache Ignite. Iskustvo Sberbanke

Komprimiranje podataka u Apache Ignite. Iskustvo SberbankePri radu s velikim količinama podataka, problem nedostatka prostora na diskovima može postati vrlo važan. Jedno od rješenja za ovaj problem je komprimiranje, zahvaljujući kojem na istoj opremi možete povećati kapacitet pohrane. U ovom ćemo članku raspraviti kako komprimiranje podataka funkcionira u Apache Ignite. Članak će opisivati samo metode komprimiranja koje su implementirane unutar proizvoda. Druge metode komprimiranja podataka (putem mreže, u memoriji) bit će izvan fokusa, bilo da su realizirane ili ne.

Dakle, kada je način trajne pohrane uključen, kao rezultat promjena podataka u predmemorijama, Ignite počinje zapisivati na disk:

  1. Sadržaj predmemorija
  2. Dnevnik unaprijed zapisivanja (Write Ahead Log, u daljnjem tekstu WAL)

Za komprimiranje WAL-a već dugo postoji mehanizam koji se naziva WAL kompresija. U nedavno objavljenom Apache Ignite 2.8 pojavila su se još dva mehanizma koja omogućuju komprimiranje podataka na disku, to su kompresija stranica diska za komprimiranje sadržaja predmemorija i kompresija snimaka stranica WAL-a za komprimiranje nekih unosa WAL-a. Opširnije o ova tri mehanizma u nastavku.

Kompresija stranica diska

Kako to funkcionira

Prvo, kratko ćemo objasniti kako Ignite pohranjuje podatke. Za pohranu se koristi stranica u memoriji. Veličina stranice postavlja se prilikom pokretanja čvora i ne može se mijenjati u kasnijim fazama, a takođe veličina stranice mora biti stepen dvojke i višekratnik veličine bloka datotečnog sustava. Stranice se učitavaju u RAM s diska prema potrebi, a veličina podataka na disku može prekoračiti dodijeljenu RAM. U slučaju nedostatka prostora u RAM-u za učitavanje stranice s diska, stare, nesadržane stranice bit će izbačene iz RAM-a.

Na disku se podaci pohranjuju na sljedeći način: za svaku particiju svake grupe predmemorije stvara se zasebna datoteka, a u toj datoteci, redoslijedom rasta indeksa, jedna za drugom idu stranice. Potpuni identifikator stranice sadrži identifikator grupe predmemorije, broj particije i indeks stranice u datoteci. Tako možemo jedinstveno odrediti datoteku i offset u datoteci za svaku stranicu pomoću punog identifikatora stranice. Više informacija o strukturi stranične memorije možete pročitati u članku na Apache Ignite Wiki: Ignite Persistent Store — iznutra.

Mehanizam kompresije stranica diska, kao što naziv sugerira, radi na razini stranica. Kada je ovaj mehanizam aktivan, rad s podacima u RAM-u odvija se bez ikakve kompresije, no tijekom spremanja stranica iz RAM-a na disk, provodi se njihovo zgušnjavanje.

Međutim, kompresija svake stranice posebno nije rješenje problema; trebamo smanjiti veličinu konačnih datoteka s podacima. Ako veličina stranice prestane biti fiksna, ne možemo više ispisivati stranice u datoteku jednu za drugom, jer to može izazvati niz problema:

  • Nećemo moći izračunati ofset stranice putem indeksa koji određuje njezinu poziciju u datoteci.
  • Nije jasno što učiniti sa stranicama koje se nalaze negdje usred datoteke i mijenjaju svoju veličinu. Ako se veličina stranice smanjuje, prostor koji je oslobodila se gubi. Ako se veličina stranice povećava, za nju je potrebno tražiti novo mjesto u datoteci.
  • Ako se stranica pomakne za broj bajtova koji nije višekratnik veličine bloka datotečnog sustava, za njezino čitanje ili pisanje bit će potrebno dodirnuti jedan blok datotečnog sustava više, što može dovesti do degradacije performansi.

Kako ne bismo rješavali te probleme na vlastitoj razini, kompresija stranica diska u Apache Ignite koristi mehanizam datotečnog sustava nazvan sparse datoteke. Sparse (rijetka) datoteka je datoteka u kojoj neka područja ispunjena nulama mogu biti označena kao "rupe". Zbog toga se blokovi datotečnog sustava ne dodjeljuju za pohranu tih rupa, čime se postiže ušteda prostora na disku.

Logično je da kako bismo oslobodili blok datotečnog sustava, veličina rupe mora biti veća ili jednaka veličini bloka datotečnog sustava, što nameće dodatna ograničenja na veličinu stranice u Apache Ignite: kako bi kompresija imala neki 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, nikada nećemo moći osloboditi nijedan blok, jer da bismo oslobodili jedan blok, komprimirana stranica mora zauzimati 0 bajta. Ako je veličina stranice jednaka veličini 2 ili 4 bloka, već ćemo moći osloboditi barem jedan blok ako se naša stranica komprimira na 50% ili 75%, redom.

Stoga, konačni opis rada mehanizma: Kada se stranica zapisuje na disk, pokušava se komprimirati stranica. Ako veličina sažete stranice omogućava oslobađanje jednog ili više blokova datotečnog sustava, stranica se zapisuje u sažetom obliku, dok se na mjestu oslobođenih blokova ubacuje "rupa" (izvodi se sistemski poziv fallocate() s oznakom "punch hole"). Ako veličina sažete stranice ne omogućava oslobađanje blokova, stranica se čuva onakva kakva jest, u nesuženom obliku. Svi ofseti stranica računaju se kao i bez kompresije, množenjem indeksa stranice s veličinom stranice. Nema potrebe za relokacijom stranica vlastitim snagama. Ofseti stranica, kao i bez kompresije, ulaze na granice blokova datotečnog sustava.

Komprimiranje podataka u Apache Ignite. Iskustvo Sberbanke

U trenutnoj implementaciji Ignite može raditi sa sparse datotekama samo pod OS Linux, stoga se kompresija diska može uključiti samo pri korištenju Ignite na ovom operacijskom sustavu.

Algoritmi kompresije koji se mogu koristiti za kompresiju stranica diska: ZSTD, LZ4, Snappy. Osim toga, postoji način rada (SKIP_GARBAGE) u kojem se samo odbacuje nepotrebno mjesto u stranici bez primjene kompresije na preostalim podacima, što omogućava smanjenje opterećenja CPU-a u usporedbi s prethodno navedenim algoritmima.

Utjecaj na performanse

Nažalost, nisam izvodio stvarna mjerenja performansi na stvarnim sustavima jer ne planiramo koristiti ovaj mehanizam u produkciji, ali možemo teoretski raspraviti gdje ćemo izgubiti, a gdje profitirati.

Za to se trebamo prisjetiti kako se čitanje i zapis stranica odvijaju prilikom njihovog poziva:

  • Prilikom izvršavanja operacije čitanja prvo se izvršava pretraživanje u RAM-u, ako je pretraživanje neuspješno, stranica se učitava u RAM iz diska istim tokom koji izvršava čitanje.
  • Prilikom izvršavanja operacije zapisivanja, stranica u RAM-u se označava kao prljava, dok se fizičko spremanje stranice na disk odmah u toku koji izvršava zapis ne odvija. Sve prljave stranice se kasnije spremaju na disk u procesu checkpointa odvojenim tokom.

Dakle, utjecaj na operacije čitanja:

  • Pozitivan (disk IO), zbog smanjenja broja pročitana bloka datotečnog sustava.
  • Negativan utjecaj (CPU), zbog dodatnog opterećenja potrebnog operativnom sustavu za rad sa sparse datotekama. Također, moguće je da će se ovdje implicitno pojaviti dodatne IO operacije za očuvanje složenije strukture sparse datoteke (nažalost, nisam upoznat sa svim detaljima rada sparse datoteka).
  • Negativan utjecaj (CPU), zbog potrebe za dekompresijom stranica.
  • Nema utjecaja na operacije pisanja.
  • Utjecaj na proces provjere točnosti (ovdje je sve slično operacijama čitanja):
  • Pozitivan utjecaj (disk IO), zbog smanjenja broja zapisanih blokova datotečnog sustava.
  • Negativan utjecaj (CPU, možda disk IO), zbog rada sa sparse datotekama.
  • Negativan utjecaj (CPU), zbog potrebe za kompresijom stranica.

Koja strana vage će prevagnuti? To uvelike ovisi o okruženju, ali naginjem prema tome da će kompresija disk stranica dovesti do degradacije performansi u većini sustava. Pogotovo s obzirom na to da testovi na drugim DBMS-ima koji koriste sličan pristup sa sparse datotekama pokazuju pad performansi kada je kompresija uključena.

Kako uključiti i konfigurirati

Kao što je već rečeno, minimalna verzija Apache Ignite koja podržava kompresiju disk stranica: 2.8 i podržava se samo na operativnom sustavu Linux. Uključivanje i konfiguracija izvode se na sljedeći način:

  • U class-path-u treba biti modul ignite-compression. Po zadano se nalazi u distribuciji Apache Ignite u direktoriju libs/optional i nije uključen u class-path. Možete jednostavno premjestiti direktorij jedan nivo više u libs i tada će prilikom pokretanja putem ignite.sh automatski biti uključen.
  • Trajna pohrana mora biti uključena (Uključuje se putem DataRegionConfiguration.setPersistenceEnabled(true)).
  • Veličina stranice mora biti veća od veličine bloka datotečnog sustava (može se postaviti pomoću DataStorageConfiguration.setPageSize() ).
  • Za svaki cache čije podatke treba komprimirati, potrebno je u konfiguraciji odabrati metodu kompresije i (po izboru) razinu kompresije (metode CacheConfiguration.setDiskPageCompression(), CacheConfiguration.setDiskPageCompressionLevel()).

WAL kompresija

Kako to funkcionira

Što je WAL i čemu služi? U vrlo kratkim crtama: to je dnevnik u koji se bilježe svi događaji koji na kraju mijenjaju predmemoriju stranica. Potreban je prvenstveno za mogućnost oporavka u slučaju pada. Svaka operacija prije nego što korisniku vrati kontrolu mora prvo zapisati događaj u WAL, kako bi u slučaju pada mogla reproducirati putem dnevnika i obnoviti sve operacije za koje je korisnik dobio uspješan odgovor, čak i ako se te operacije nisu uspjele odraziti u predmemoriji stranica na disku (već je opisano da se stvarno zapisivanje u predmemoriju stranica vrši u procesu koji se naziva „checkpoin“ s nekim zakašnjenjem od strane zasebnih niti).

Zapisi u WAL dijele se na logičke i fizičke. Logičke — to su sami ključevi i vrijednosti. Fizikalne — odražavaju promjene stranica u predmemoriji stranica. Dok logički zapisi mogu biti korisni i za neke druge slučajeve, fizički zapisi su potrebni samo za oporavak u slučaju pada i potrebni su zapisi samo od posljednjeg uspješnog checkpointa. Ovdje se nećemo upuštati u pojedinosti i objašnjavati zašto to tako funkcionira, ali onima koje to zanima, mogu se obratiti već spomenutom članku na Apache Ignite Wiki: Ignite Persistent Store — iznutra.

Na jedan logički zapis često dolazi nekoliko fizičkih zapisa. To znači, na primjer, da jedna operacija put u predmemoriji zahvaća nekoliko stranica u strančnoj memoriji (stranicu s podacima, stranice s indeksima, stranice s free-listama). U nekim sintetičkim testovima primijetio sam da su fizički zapisi zauzimali do 90% volumena WAL datoteke. Pri tome su potrebni vrlo kratko vrijeme (prema zadanim postavkama, interval između checkpointa je 3 minute). Logično bi bilo riješiti se tih podataka nakon što izgube svoju aktualnost. Upravo to radi mehanizam WAL kompakcija, oslobađa se fizičkih zapisa i kompresira preostale logičke zapise uz pomoć zip-a, pri čemu se veličina datoteke značajno smanjuje (ponekad i do desetak puta).

Fizički WAL sastoji se od nekoliko segmenata (po defaultu 10) fiksne veličine (po defaultu 64MB), koji se prepisuju u krug. Kada se trenutni segment napuni, sljedeći segment se dodjeljuje trenutnom, a ispunjeni segment se kopira u arhivu zasebnim tokom. WAL kompresija već radi s arhivskim segmentima. Također, zasebnim tokom prati izvršenje kontrolne točke i započinje kompresiju arhivskih segmenata, fizičke zapise za koje više nisu potrebni.

Komprimiranje podataka u Apache Ignite. Iskustvo Sberbanke

Utjecaj na performanse

Budući da WAL kompresija radi zasebnim tokom, ne bi trebala imati direktnog utjecaja na izvršene operacije. No, ipak daje dodatno pozadinsko opterećenje na CPU (kompresija) i disk (čitajući svaki WAL segment iz arhive i zapisivši komprimirane segmente), stoga, ako sustav radi na rubu mogućnosti, to će također dovesti do pogoršanja performansi.

Kako uključiti i konfigurirati

WAL kompresiju možete uključiti pomoću svojstva WalCompactionEnabled u DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). Također, pomoću metode DataStorageConfiguration.setWalCompactionLevel() možete postaviti razinu kompresije, ako vam ne odgovara zadana vrijednost (BEST_SPEED).

WAL snapshot kompresija stranica

Kako to funkcionira

Već smo utvrdili da se WAL zapisi dijele na logičke i fizičke. Za svaku promjenu svake stranice u memoriji stranica formira se fizički zapis WAL-a. Fizički zapisi, s druge strane, također se dijele na 2 podvrste: zapis snimke stranice i delta zapis. Svaki put kada promijenimo nešto na stranici i prebacimo je iz čistog stanja u prljavo, u WAL se pohranjuje puna kopija te stranice (zapis snimke stranice — snapshot stranice). Čak i ako promijenimo samo jedan bajt, u WAL će se pohraniti zapis veličine nešto veće od veličine stranice. Ako promijenimo nešto na već prljavoj stranici, tada se u WAL formira delta zapis, u kojem su zabilježene samo promjene u odnosu na prethodno stanje stranice, ali ne cijela stranica. Budući da se vraćanje stanja stranica iz prljavog u čist običava tijekom procesa kontrolne točke, odmah nakon početka kontrolne točke gotovo svi fizički zapisi će se sastojati samo od snimaka stranica (jer su sve stranice odmah nakon početka kontrolne točke čiste), a zatim, kako se bližimo sljedećoj kontrolnoj točki, udio delta zapisa počinje rasti i opet se vraća na početku sljedeće kontrolne točke. Mjerenja na nekim sintetičkim testovima pokazala su da udio snimaka stranica u ukupnom volumenu fizičkih zapisa doseže 90%.

Ideja kompresije snimaka stranica WAL-a je da se komprimiraju snimci stranica koristeći već gotov alat za kompresiju stranica (vidi kompresiju disk stranica). Pri tome se u WAL-u zapisi pohranjuju fizički u append-only režimu i nije potrebno povezivati zapise s granicama blokova datotečnog sustava, stoga ovdje, za razliku od mehanizma kompresije disk stranica, sparse datoteke nisu potrebne, pa će taj mehanizam raditi ne samo na Linux operacijskim sustavima. Osim toga, ne brine nas koliko smo moćno uspjeli komprimirati stranicu. Čak i ako smo oslobodili 1 bajt, to je već pozitivan rezultat i možemo pohranjivati komprimirane podatke u WAL, za razliku od kompresije disk stranica, gdje pohranjujemo komprimiranu stranicu samo ako smo oslobodili više od 1 bloka datotečnog sustava.

Stranice su dobro komprimirani podaci, a njihov udio u ukupnom volumenu WAL-a je vrlo visok. Tako da ne mijenjajući format WAL datoteke možemo dobiti značajno smanjenje njezine veličine. Kompresija logičkih zapisa također bi zahtijevala promjenu formata i gubitak kompatibilnosti, primjerice, za vanjske korisnike koje logički zapisi mogu zanimati, a ne bi donijela značajno smanjenje volumena datoteke.

Kao i za kompresiju disk stranica, za kompresiju snapshot-a WAL stranica mogu se koristiti algoritmi kompresije ZSTD, LZ4, Snappy, kao i način SKIP_GARBAGE.

Utjecaj na performanse

Kako nije teško primijetiti, izravno uključivanje kompresije snapshot-a WAL stranica utječe samo na tokove koji upisuju podatke u memoriju stranica, tj. na one tokove koji mijenjaju podatke u cache-u. Čitanje iz WAL fizičkih zapisa događa se samo jedanput, u trenutku podizanja čvora nakon pada (i to samo u slučaju pada tijekom checkpointa).

Na tokove koji mijenjaju podatke ovo utječe na sljedeći način: imamo negativan učinak (CPU) zbog potrebe da svaki put komprimiramo stranicu prije upisa na disk i pozitivan učinak (disk IO) zbog smanjenja količine zapisanih podataka. U skladu s tim, ovdje je sve jednostavno, ako je performansa sustava ograničena s CPU-a, dolazimo do malog pogoršanja, ako je na disku ulaz/izlaz — dobijemo porast.

Posredno smanjenje veličine WAL-a također pozitivno utječe na tokove koji arhiviraju segmente WAL-a i na tokove WAL kompaktiranja.

Stvarni testovi performansi u našem okruženju na sintetičkim podacima pokazali su mali porast (propusnost je porasla za 10%-15%, latencija je smanjena za 10%-15%).

Kako uključiti i konfigurirati

Minimalna verzija Apache Ignite: 2.8. Aktivacija i postavljanje provode se na sljedeći način:

  • U class-path-u treba biti modul ignite-compression. Po zadano se nalazi u distribuciji Apache Ignite u direktoriju libs/optional i nije uključen u class-path. Možete jednostavno premjestiti direktorij jedan nivo više u libs i tada će prilikom pokretanja putem ignite.sh automatski biti uključen.
  • Trajna pohrana mora biti uključena (Uključuje se putem DataRegionConfiguration.setPersistenceEnabled(true)).
  • Mora biti postavljen način kompresije pomoću metode DataStorageConfiguration.setWalPageCompression(), po defaultu, kompresija je isključena (način DISABLED).
  • Opcionalno je moguće postaviti stupanj kompresije pomoću metode DataStorageConfiguration.setWalPageCompression(), dopuštene vrijednosti za svaki od načina potraži u javadoc-u za metodu.

Zaključak

Razmatrani mehanizmi kompresije podataka u Apache Ignite mogu se koristiti neovisno jedni od drugih, ali su također dopuštene i bilo kakve njihove kombinacije. Razumijevanje principa njihovog rada omogućit će vam da odredite koliko su prikladni za vaše zadatke u vašem okruženju i što ćete morati žrtvovati pri njihovom korištenju. Kompresija disk stranica je namijenjena za kompresiju osnovnog skladišta i može dati srednju razinu kompresije. Kompresija snimaka WAL stranica će dati srednju razinu kompresije već postojećim WAL datotekama, pri čemu će vjerojatno čak i povećati performanse. WAL kompakcija neće imati pozitivan utjecaj na performanse, ali će maksimalno smanjiti veličinu WAL datoteka uklanjanjem fizičkih zapisa.

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster