Comprimarea datelor în Apache Ignite. experiența lui Sber

Comprimarea datelor în Apache Ignite. experiența lui SberCând lucrați cu volume mari de date, poate apărea uneori problema lipsei de spațiu pe disc. O modalitate de a rezolva această problemă este compresia, datorită căreia, pe același echipament, vă puteți permite să creșteți volumele de stocare. În acest articol, ne vom uita la modul în care funcționează compresia datelor în Apache Ignite. Acest articol va descrie numai metodele de compresie de disc implementate în produs. Alte metode de compresie a datelor (prin rețea, în memorie), indiferent dacă sunt implementate sau nu, vor rămâne în afara domeniului de aplicare.

Deci, cu modul de persistență activat, ca urmare a modificărilor datelor din cache, Ignite începe să scrie pe disc:

  1. Conținutul cache-urilor
  2. Write Ahead Log (în continuare pur și simplu WAL)

Există un mecanism pentru compresia WAL de ceva timp, numit compactare WAL. Apache Ignite 2.8 lansat recent a introdus încă două mecanisme care vă permit să comprimați datele de pe disc: compresia paginilor de disc pentru comprimarea conținutului cache-urilor și compresia instantanee a paginii WAL pentru comprimarea unor intrări WAL. Mai multe detalii despre toate aceste trei mecanisme mai jos.

Comprimarea paginii pe disc

Cum funcționează

În primul rând, să aruncăm o privire foarte scurtă asupra modului în care Ignite stochează datele. Memoria de pagină este folosită pentru stocare. Mărimea paginii este setată la începutul nodului și nu poate fi modificată în etapele ulterioare; de ​​asemenea, dimensiunea paginii trebuie să fie o putere de doi și un multiplu al dimensiunii blocului sistemului de fișiere. Paginile sunt încărcate în RAM de pe disc după cum este necesar; dimensiunea datelor de pe disc poate depăși cantitatea de RAM alocată. Dacă nu există suficient spațiu în RAM pentru a încărca o pagină de pe disc, paginile vechi, nu mai utilizate, vor fi evacuate din RAM.

Datele sunt stocate pe disc sub următoarea formă: se creează un fișier separat pentru fiecare partiție a fiecărui grup de cache; în acest fișier, paginile apar una după alta în ordine crescătoare a indexului. Identificatorul complet de pagină conține identificatorul grupului de cache, numărul partiției și indexul paginii din fișier. Astfel, folosind identificatorul de pagină completă, putem determina în mod unic fișierul și offset-ul din fișier pentru fiecare pagină. Puteți citi mai multe despre memoria de paginare în articolul Apache Ignite Wiki: Ignite Persistent Store - sub capotă.

Mecanismul de comprimare a paginii de disc, așa cum ați putea ghici din nume, funcționează la nivel de pagină. Când acest mecanism este activat, datele din RAM sunt procesate așa cum sunt, fără nicio compresie, dar când paginile sunt salvate de pe RAM pe disc, acestea sunt comprimate.

Dar comprimarea fiecărei pagini individual nu este o soluție la problemă; trebuie să reduceți cumva dimensiunea fișierelor de date rezultate. Dacă dimensiunea paginii nu mai este fixă, nu mai putem scrie pagini în fișier una după alta, deoarece acest lucru poate crea o serie de probleme:

  • Folosind indexul paginii, nu vom putea calcula offset-ul cu care se află în fișier.
  • Nu este clar ce să faci cu paginile care nu sunt la sfârșitul fișierului și își schimbă dimensiunea. Dacă dimensiunea paginii scade, spațiul pe care l-a eliberat dispare. Dacă dimensiunea paginii crește, trebuie să căutați un loc nou în fișier pentru aceasta.
  • Dacă o pagină se mișcă cu un număr de octeți care nu este un multiplu al dimensiunii blocului sistemului de fișiere, atunci citirea sau scrierea acesteia va necesita atingerea unui alt bloc de sistem de fișiere, ceea ce poate duce la degradarea performanței.

Pentru a evita rezolvarea acestor probleme la propriul nivel, compresia paginilor de disc în Apache Ignite utilizează un mecanism de sistem de fișiere numit fișiere rare. Un fișier rar este unul în care unele regiuni umplute cu zero pot fi marcate ca „găuri”. În acest caz, nu vor fi alocate blocuri de sistem de fișiere pentru a stoca aceste găuri, rezultând economii de spațiu pe disc.

Este logic ca pentru a elibera un bloc de sistem de fișiere, dimensiunea găurii trebuie să fie mai mare sau egală cu blocul de sistem de fișiere, ceea ce impune o limitare suplimentară a dimensiunii paginii și Apache Ignite: pentru ca compresia să aibă vreun efect, dimensiunea paginii trebuie să fie strict mai mare decât dimensiunea blocului sistemului de fișiere. Dacă dimensiunea paginii este egală cu dimensiunea blocului, atunci nu vom putea niciodată să eliberăm un singur bloc, deoarece pentru a elibera un singur bloc, pagina comprimată trebuie să ocupe 0 octeți. Dacă dimensiunea paginii este egală cu dimensiunea de 2 sau 4 blocuri, vom putea deja să eliberăm cel puțin un bloc dacă pagina noastră este comprimată la cel puțin 50% sau, respectiv, 75%.

Astfel, descrierea finală a modului în care funcționează mecanismul: Când scrieți o pagină pe disc, se încearcă comprimarea paginii. Dacă dimensiunea paginii comprimate permite eliberarea unuia sau mai multor blocuri de sistem de fișiere, atunci pagina este scrisă sub formă comprimată și se face o „găuri” în locul blocurilor eliberate (se execută un apel de sistem fallocate() cu steagul perforat). Dacă dimensiunea paginii comprimate nu permite eliberarea blocurilor, pagina este salvată ca atare, necomprimată. Toate decalările paginii sunt calculate la fel ca și fără compresie, prin înmulțirea indexului paginii cu dimensiunea paginii. Nu este necesară mutarea paginilor pe cont propriu. Decalajele de pagină, la fel ca și fără compresie, se încadrează la limitele blocurilor de sistem de fișiere.

Comprimarea datelor în Apache Ignite. experiența lui Sber

În implementarea actuală, Ignite poate funcționa numai cu fișiere rare sub sistemul de operare Linux; în consecință, compresia paginilor de disc poate fi activată numai atunci când se utilizează Ignite pe acest sistem de operare.

Algoritmi de compresie care pot fi utilizați pentru compresia paginilor de disc: ZSTD, LZ4, Snappy. În plus, există un mod de operare (SKIP_GARBAGE), în care doar spațiul nefolosit din pagină este aruncat fără a aplica compresie asupra datelor rămase, ceea ce reduce sarcina CPU-ului în comparație cu algoritmii enumerați anterior.

Impactul asupra performanței

Din păcate, nu am efectuat măsurători efective de performanță pe standuri reale, deoarece nu intenționăm să folosim acest mecanism în producție, dar putem specula teoretic unde vom pierde și unde vom câștiga.

Pentru a face acest lucru, trebuie să ne amintim cum sunt citite și scrise paginile atunci când sunt accesate:

  • Când se efectuează o operație de citire, aceasta este mai întâi căutată în RAM; dacă căutarea nu reușește, pagina este încărcată în RAM de pe disc de același fir care efectuează citirea.
  • Când se efectuează o operație de scriere, pagina din RAM este marcată ca murdară, dar pagina nu este salvată fizic pe disc imediat de firul care efectuează scrierea. Toate paginile murdare sunt salvate pe disc mai târziu în procesul punctului de control în fire separate.

Deci impactul asupra operațiunilor de citire este:

  • Pozitiv (disc IO), din cauza scăderii numărului de blocuri de fișiere citite.
  • Negativ (CPU), din cauza încărcării suplimentare cerute de sistemul de operare pentru a lucra cu fișiere rare. De asemenea, este posibil ca aici să apară implicit operațiuni IO suplimentare pentru a salva o structură de fișiere mai complexă (din păcate, nu sunt familiarizat cu toate detaliile despre cum funcționează fișierele rare).
  • Negativ (CPU), din cauza necesității de a decomprima paginile.
  • Nu există niciun impact asupra operațiunilor de scriere.
  • Impact asupra procesului punctului de control (totul aici este similar cu operațiunile de citire):
  • Pozitiv (disc IO), din cauza scăderii numărului de blocuri scrise de sistem de fișiere.
  • Negativ (CPU, posibil IO pe disc), din cauza lucrului cu fișiere rare.
  • Negativ (CPU), din cauza necesității comprimării paginii.

Care parte a cântarului va înclina cântarul? Toate acestea depind foarte mult de mediu, dar sunt înclinat să cred că compresia paginii de disc va duce cel mai probabil la degradarea performanței pe majoritatea sistemelor. Mai mult, testele pe alte SGBD-uri care folosesc o abordare similară cu fișiere rare arată o scădere a performanței atunci când compresia este activată.

Cum se activează și se configurează

După cum am menționat mai sus, versiunea minimă de Apache Ignite care acceptă compresia paginilor de disc este 2.8 și este acceptat doar sistemul de operare Linux. Activați și configurați după cum urmează:

  • Trebuie să existe un modul ignite-compression în calea clasei. În mod implicit, se află în distribuția Apache Ignite în directorul libs/opțional și nu este inclus în calea clasei. Pur și simplu puteți muta directorul cu un nivel în sus la libs și apoi, când îl rulați prin ignite.sh, va fi activat automat.
  • Persistența trebuie să fie activată (activată prin DataRegionConfiguration.setPersistenceEnabled(true)).
  • Dimensiunea paginii trebuie să fie mai mare decât dimensiunea blocului sistemului de fișiere (o puteți seta folosind DataStorageConfiguration.setPageSize() ).
  • Pentru fiecare cache ale cărei date trebuie comprimate, trebuie să configurați metoda de compresie și (opțional) nivelul de compresie (metode CacheConfiguration.setDiskPageCompression() , CacheConfiguration.setDiskPageCompressionLevel()).

Compactare WAL

Cum funcționează

Ce este WAL și de ce este necesar? Foarte pe scurt: acesta este un jurnal care conține toate evenimentele care modifică în cele din urmă stocarea paginii. Este necesar în primul rând pentru a vă putea recupera în caz de cădere. Orice operațiune, înainte de a da controlul utilizatorului, trebuie mai întâi să înregistreze un eveniment în WAL, astfel încât, în caz de eșec, să poată fi redate în jurnal și restaurate toate operațiunile pentru care utilizatorul a primit un răspuns cu succes, chiar dacă aceste operațiuni nu a avut timp să se reflecte în stocarea paginii de pe disc (deja mai sus S-a descris că scrierea efectivă în magazinul de pagini se face într-un proces numit „checkpointing” cu o oarecare întârziere prin fire separate).

Intrările în WAL sunt împărțite în logice și fizice. Cele booleene sunt cheile și valorile însele. Fizic - reflectă modificările aduse paginilor din magazinul de pagini. În timp ce înregistrările logice pot fi utile în alte cazuri, înregistrările fizice sunt necesare doar pentru recuperare în caz de accident, iar înregistrările sunt necesare doar de la ultimul punct de control reușit. Aici nu vom intra în detaliu și vom explica de ce funcționează astfel, dar cei interesați se pot referi la articolul deja menționat de pe Apache Ignite Wiki: Ignite Persistent Store - sub capotă.

Există adesea mai multe înregistrări fizice pentru fiecare înregistrare logică. Adică, de exemplu, o operație de introducere în cache afectează mai multe pagini din memoria paginii (o pagină cu datele în sine, pagini cu indexuri, pagini cu liste libere). În unele teste sintetice, am constatat că înregistrările fizice ocupau până la 90% din fișierul WAL. Cu toate acestea, acestea sunt necesare pentru o perioadă foarte scurtă de timp (în mod implicit, intervalul dintre punctele de control este de 3 minute). Ar fi logic să scăpăm de aceste date după ce își pierde relevanța. Este exact ceea ce face mecanismul de compactare WAL: scapă de înregistrările fizice și comprimă înregistrările logice rămase folosind zip, în timp ce dimensiunea fișierului este redusă foarte semnificativ (uneori de zeci de ori).

Din punct de vedere fizic, WAL constă din mai multe segmente (10 implicit) de o dimensiune fixă ​​(64MB implicit), care sunt suprascrise într-o manieră circulară. De îndată ce segmentul curent este umplut, următorul segment este atribuit ca curent, iar segmentul umplut este copiat în arhivă printr-un fir separat. Compactarea WAL funcționează deja cu segmente de arhivă. De asemenea, ca fir separat, monitorizează execuția punctului de control și începe compresia în segmentele de arhivă pentru care nu mai sunt necesare înregistrări fizice.

Comprimarea datelor în Apache Ignite. experiența lui Sber

Impactul asupra performanței

Deoarece compactarea WAL rulează ca un fir separat, nu ar trebui să existe un impact direct asupra operațiunilor efectuate. Dar încă pune încărcare suplimentară de fundal pe CPU (compresie) și pe disc (citirea fiecărui segment WAL din arhivă și scrierea segmentelor comprimate), așa că dacă sistemul rulează la capacitatea maximă, va duce și la degradarea performanței.

Cum se activează și se configurează

Puteți activa compactarea WAL folosind proprietatea WalCompactionEnabled в DataStorageConfiguration (DataStorageConfiguration.setWalCompactionEnabled(true)). De asemenea, folosind metoda DataStorageConfiguration.setWalCompactionLevel(), puteți seta nivelul de compresie dacă nu sunteți mulțumit de valoarea implicită (BEST_SPEED).

Comprimarea instantanee a paginii WAL

Cum funcționează

Am aflat deja că în WAL înregistrările sunt împărțite în logice și fizice. Pentru fiecare modificare a fiecărei pagini, o înregistrare WAL fizică este generată în memoria paginii. Înregistrările fizice, la rândul lor, sunt de asemenea împărțite în 2 subtipuri: înregistrarea instantanee a paginii și înregistrarea delta. De fiecare dată când schimbăm ceva pe o pagină și îl transferăm dintr-o stare curată într-o stare murdară, o copie completă a acestei pagini este stocată în WAL (înregistrare instantanee a paginii). Chiar dacă am schimbat doar un octet în WAL, înregistrarea va fi puțin mai mare decât dimensiunea paginii. Dacă schimbăm ceva pe o pagină deja murdară, în WAL se formează o înregistrare delta, care reflectă doar modificări față de starea anterioară a paginii, dar nu întreaga pagină. Deoarece resetarea stării paginilor de la murdar la curat se efectuează în timpul procesului punctului de control, imediat după începerea punctului de control, aproape toate înregistrările fizice vor consta doar din instantanee ale paginilor (deoarece toate paginile imediat după începerea punctului de control sunt curate) , apoi pe măsură ce ne apropiem de următorul punct de control, fracția de înregistrare delta începe să crească și să se reseteze din nou la începutul următorului punct de control. Măsurătorile efectuate la unele teste sintetice au arătat că ponderea instantaneelor ​​de pagină în volumul total al înregistrărilor fizice ajunge la 90%.

Ideea compresiei instantanee a paginii WAL este de a comprima instantaneele paginii folosind un instrument de compresie a paginii gata făcut (vezi compresia paginii de pe disc). În același timp, în WAL, înregistrările sunt salvate secvențial în modul numai adăugare și nu este nevoie de a lega înregistrările la granițele blocurilor sistemului de fișiere, așa că aici, spre deosebire de mecanismul de compresie a paginii de disc, nu avem nevoie de fișiere rare la toate; în consecință, acest mecanism va funcționa nu numai pe sistemul de operare Linux. În plus, nu mai contează pentru noi cât de mult am reușit să comprimăm pagina. Chiar dacă am eliberat 1 octet, acesta este deja un rezultat pozitiv și putem salva datele comprimate în WAL, spre deosebire de compresia paginii de disc, unde salvăm pagina comprimată doar dacă am eliberat mai mult de 1 bloc de sistem de fișiere.

Paginile sunt date foarte compresibile, ponderea lor în volumul total WAL este foarte mare, astfel încât fără a schimba formatul fișierului WAL putem obține o reducere semnificativă a dimensiunii acestuia. Comprimarea, inclusiv înregistrările logice, ar necesita o modificare a formatului și pierderea compatibilității, de exemplu, pentru consumatorii externi care ar putea fi interesați de înregistrările logice, dar nu ar duce la o reducere semnificativă a dimensiunii fișierului.

Ca și în cazul compresiei paginilor de disc, compresia instantanee a paginii WAL poate utiliza algoritmi de compresie ZSTD, LZ4, Snappy, precum și modul SKIP_GARBAGE.

Impactul asupra performanței

Nu este greu de observat că activarea directă a compresiei instantanee a paginii WAL afectează numai firele care scriu date în memoria paginii, adică acele fire care modifică datele din cache. Citirea înregistrărilor fizice din WAL are loc o singură dată, în momentul în care nodul este ridicat după o cădere (și numai dacă cade în timpul unui punct de control).

Acest lucru afectează firele de execuție care modifică datele în felul următor: obținem un efect negativ (CPU) din cauza necesității de a comprima pagina de fiecare dată înainte de a scrie pe disc și un efect pozitiv (disk IO) datorită unei reduceri a cantității de datele scrise. În consecință, totul este simplu aici: dacă performanța sistemului este limitată de CPU, obținem o ușoară degradare, dacă este limitată de I/O disc, obținem o creștere.

Indirect, reducerea dimensiunii WAL afectează, de asemenea, (pozitiv) fluxurile care aruncă segmente WAL în arhivă și fluxurile de compactare WAL.

Testele de performanță reale din mediul nostru folosind date sintetice au arătat o ușoară creștere (debitul a crescut cu 10%-15%, latența a scăzut cu 10%-15%).

Cum se activează și se configurează

Versiunea minimă Apache Ignite: 2.8. Activați și configurați după cum urmează:

  • Trebuie să existe un modul ignite-compression în calea clasei. În mod implicit, se află în distribuția Apache Ignite în directorul libs/opțional și nu este inclus în calea clasei. Pur și simplu puteți muta directorul cu un nivel în sus la libs și apoi, când îl rulați prin ignite.sh, va fi activat automat.
  • Persistența trebuie să fie activată (activată prin DataRegionConfiguration.setPersistenceEnabled(true)).
  • Modul de compresie trebuie setat folosind metoda DataStorageConfiguration.setWalPageCompression(), compresia este dezactivată implicit (mod DISABLED).
  • Opțional, puteți seta nivelul de compresie folosind metoda DataStorageConfiguration.setWalPageCompression(), consultați javadoc pentru metoda pentru valori valide pentru fiecare mod.

Concluzie

Mecanismele considerate de comprimare a datelor din Apache Ignite pot fi utilizate independent unele de altele, dar orice combinație a acestora este, de asemenea, acceptabilă. Înțelegerea modului în care funcționează vă va permite să determinați cât de potrivite sunt pentru sarcinile dvs. din mediul dvs. și ce va trebui să sacrificați atunci când le utilizați. Compresia paginii de disc este concepută pentru a comprima stocarea principală și poate oferi un raport de compresie mediu. Comprimarea instantanee a paginii WAL va oferi un grad mediu de compresie pentru fișierele WAL și, cel mai probabil, chiar va îmbunătăți performanța. Compactarea WAL nu va avea un efect pozitiv asupra performanței, dar va reduce dimensiunea fișierelor WAL cât mai mult posibil prin eliminarea înregistrărilor fizice.

Sursa: www.habr.com

Adauga un comentariu