Cassandra. Cum să nu mori dacă știi doar Oracle

Hei Habr.

Numele meu este Misha Butrimov, aș vrea să vă povestesc puțin despre Cassandra. Povestea mea va fi utilă celor care nu au întâlnit niciodată baze de date NoSQL - are o mulțime de caracteristici de implementare și capcane despre care trebuie să știți. Și dacă nu ați văzut altceva decât Oracle sau orice altă bază de date relațională, aceste lucruri vă vor salva viața.

Ce e atât de bun la Cassandra? Este o bază de date NoSQL concepută fără un singur punct de eșec care se scalează bine. Dacă trebuie să adăugați câțiva teraocteți pentru o bază de date, pur și simplu adăugați noduri în inel. Îl extindeți la alt centru de date? Adăugați noduri la cluster. Creșteți RPS-ul procesat? Adăugați noduri la cluster. Funcționează și în direcția opusă.

Cassandra. Cum să nu mori dacă știi doar Oracle

La ce altceva se pricepe? Este vorba despre gestionarea multor cereri. Dar cât înseamnă mult? 10, 20, 30, 40 de mii de solicitări pe secundă nu înseamnă mult. 100 de mii de solicitări pe secundă pentru înregistrare - de asemenea. Sunt companii care au spus că păstrează 2 milioane de solicitări pe secundă. Probabil că vor trebui să creadă.

Și, în principiu, Cassandra are o mare diferență față de datele relaționale - nu seamănă deloc cu acestea. Și acest lucru este foarte important de reținut.

Nu tot ceea ce arată la fel funcționează la fel

Odată, un coleg a venit la mine și a întrebat: „Iată un limbaj de interogare CQL Cassandra și are o declarație select, are unde, are și. Scriu scrisori și nu merge. De ce?". A trata Cassandra ca pe o bază de date relațională este modalitatea perfectă de a te sinucide violent. Și nu îl promovez, este interzis în Rusia. Pur și simplu vei proiecta ceva greșit.

De exemplu, un client vine la noi și ne spune: „Să construim o bază de date pentru seriale TV sau o bază de date pentru un director de rețete. Vom avea feluri de mâncare acolo sau o listă de seriale TV și actori.” Spunem cu bucurie: „Hai să mergem!” Trimiteți doar doi octeți, câteva semne și gata, totul va funcționa foarte rapid și fiabil. Și totul este în regulă până vin clienții și spun că și gospodinele rezolvă problema inversă: au o listă de produse și vor să știe ce fel de mâncare vor să gătească. Ești mort.

Acest lucru se datorează faptului că Cassandra este o bază de date hibridă: oferă simultan o valoare cheie și stochează datele în coloane largi. În Java sau Kotlin, ar putea fi descris astfel:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

Adică o hartă care conține și o hartă sortată. Prima cheie a acestei hărți este cheia Rând sau cheia Partiției - cheia de partiționare. A doua cheie, care este cheia unei hărți deja sortate, este cheia Clustering.

Pentru a ilustra distribuția bazei de date, să desenăm trei noduri. Acum trebuie să înțelegeți cum să descompuneți datele în noduri. Pentru că dacă îngrămăm totul într-unul singur (apropo, pot fi o mie, două mii, cinci - câte vrei), nu este vorba chiar despre distribuție. Prin urmare, avem nevoie de o funcție matematică care va returna un număr. Doar un număr, un int lung care va intra într-un anumit interval. Și vom avea un nod responsabil pentru un interval, al doilea pentru al doilea, al n-lea pentru al n-lea.

Cassandra. Cum să nu mori dacă știi doar Oracle

Acest număr este luat folosind o funcție hash, care este aplicată la ceea ce numim cheia de partiție. Aceasta este coloana care este specificată în directiva cheie primară și aceasta este coloana care va fi prima și cea mai de bază cheie a hărții. Acesta determină ce nod va primi ce date. Un tabel este creat în Cassandra cu aproape aceeași sintaxă ca în SQL:

CREATE TABLE users (
	user_id uu id,
	name text,
	year int,
	salary float,
	PRIMARY KEY(user_id)

)

Cheia primară în acest caz constă dintr-o coloană și este, de asemenea, cheia de partiționare.

Cum vor performa utilizatorii noștri? Unii vor merge la un nod, alții la altul și alții la un al treilea. Rezultatul este un tabel hash obișnuit, cunoscut și ca hartă, cunoscut și ca dicționar în Python, sau o structură simplă a valorii cheie din care putem citi toate valorile, citi și scrie după cheie.

Cassandra. Cum să nu mori dacă știi doar Oracle

Selectați: când permiteți filtrarea se transformă în scanare completă sau ce nu trebuie făcut

Să scriem o declarație selectă: select * from users where, userid = . Se dovedește ca în Oracle: scriem select, specificăm condițiile și totul funcționează, utilizatorii îl primesc. Dar dacă selectezi, de exemplu, un utilizator cu un anumit an de naștere, Cassandra se plânge că nu poate îndeplini cererea. Pentru că ea nu știe absolut nimic despre modul în care distribuim datele despre anul nașterii - are o singură coloană indicată ca cheie. Apoi ea spune: „Bine, încă pot îndeplini această solicitare. Adăugați filtrarea permisă." Adăugăm directiva, totul funcționează. Și în acest moment se întâmplă ceva groaznic.

Când rulăm pe date de testare, totul este în regulă. Și când executați o interogare în producție, unde avem, de exemplu, 4 milioane de înregistrări, atunci totul nu este foarte bun pentru noi. Deoarece filtrarea permisă este o directivă care îi permite lui Cassandra să colecteze toate datele din acest tabel de la toate nodurile, toate centrele de date (dacă sunt multe dintre ele în acest cluster) și abia apoi să le filtreze. Acesta este un analog al Scanării complete și aproape nimeni nu este încântat de el.

Dacă am avea nevoie doar de utilizatori după ID, am fi bine cu asta. Dar uneori trebuie să scriem alte interogări și să impunem alte restricții asupra selecției. Prin urmare, să ne amintim: aceasta este o hartă care are o cheie de partiționare, dar în interiorul ei este o hartă sortată.

Și ea are, de asemenea, o cheie, pe care o numim Cheia de Clustering. Această cheie, care, la rândul său, este formată din coloanele pe care le selectăm, cu ajutorul cărora Cassandra înțelege cum sunt sortate fizic datele sale și vor fi amplasate pe fiecare nod. Adică, pentru o cheie de partiție, cheia de Clustering vă va spune exact cum să introduceți datele în acest arbore, ce loc va ocupa acolo.

Acesta este într-adevăr un arbore, un comparator este pur și simplu numit acolo, căruia îi trecem un anumit set de coloane sub forma unui obiect și este, de asemenea, specificat ca o listă de coloane.

CREATE TABLE users_by_year_salary_id (
	user_id uuid,
	name text,
	year int,
	salary float,
	PRIMARY KEY((year), salary, user_id)

Acordați atenție directivei cheie primară; primul său argument (în cazul nostru, anul) este întotdeauna cheia partiției. Poate consta din una sau mai multe coloane, nu contează. Dacă există mai multe coloane, trebuie eliminată din nou între paranteze, astfel încât preprocesorul de limbă să înțeleagă că aceasta este cheia primară, iar în spatele ei toate celelalte coloane sunt cheia de clusterizare. În acest caz, acestea vor fi transmise în comparator în ordinea în care apar. Adică, prima coloană este mai semnificativă, a doua este mai puțin semnificativă și așa mai departe. Modul în care scriem, de exemplu, este egal cu câmpurile pentru clasele de date: listăm câmpurile, iar pentru ele scriem care sunt mai mari și care sunt mai mici. În Cassandra, acestea sunt, relativ vorbind, câmpurile clasei de date, cărora li se vor aplica egalele scrise pentru aceasta.

Stabilim sortarea și impunem restricții

Trebuie să rețineți că ordinea de sortare (descrescătoare, ascendentă, orice) este setată în același moment în care este creată cheia și nu poate fi schimbată ulterior. Determină fizic cum vor fi sortate datele și cum vor fi stocate. Dacă trebuie să modificați cheia de Clustering sau ordinea de sortare, va trebui să creați un nou tabel și să transferați datele în acesta. Acest lucru nu va funcționa cu unul existent.

Cassandra. Cum să nu mori dacă știi doar Oracle

Ne-am umplut tabelul cu utilizatori și am văzut că aceștia au căzut într-un inel, mai întâi după anul nașterii, iar apoi în interior pe fiecare nod după salariu și ID-ul utilizatorului. Acum putem selecta prin impunerea de restricții.

Apare din nou cel de lucru where, and, și primim utilizatori și totul este bine din nou. Dar dacă încercăm să folosim doar o parte din cheia de Clustering și una mai puțin semnificativă, atunci Cassandra se va plânge imediat că nu poate găsi locul din harta noastră unde acest obiect, care are aceste câmpuri pentru comparatorul nul, și acesta. tocmai a fost stabilit, - unde zace. Va trebui să scot din nou toate datele din acest nod și să le filtrez. Și acesta este un analog al Scanării complete într-un nod, acest lucru este rău.

În orice situație neclară, creați un nou tabel

Dacă vrem să putem viza utilizatorii după ID, sau după vârstă, sau după salariu, ce ar trebui să facem? Nimic. Folosește doar două tabele. Dacă trebuie să ajungeți la utilizatori în trei moduri diferite, vor exista trei tabele. S-au dus vremurile în care economisim spațiu pe șurub. Aceasta este cea mai ieftină resursă. Costă mult mai puțin decât timpul de răspuns, ceea ce poate fi în detrimentul utilizatorului. Este mult mai plăcut pentru utilizator să primească ceva într-o secundă decât în ​​10 minute.

Schimbăm spațiu inutil și date denormalizate pentru capacitatea de a scala bine și de a funcționa fiabil. La urma urmei, de fapt, un cluster care constă din trei centre de date, fiecare dintre ele având cinci noduri, cu un nivel acceptabil de conservare a datelor (când nimic nu se pierde), este capabil să supraviețuiască complet morții unui centru de date. Și încă două noduri în fiecare dintre celelalte două. Și abia după aceasta încep problemele. Aceasta este o redundanță destul de bună, merită câteva unități SSD și procesoare suplimentare. Prin urmare, pentru a utiliza Cassandra, care nu este niciodată SQL, în care nu există relații, chei străine, trebuie să cunoașteți reguli simple.

Proiectăm totul conform solicitării dumneavoastră. Principalul lucru nu sunt datele, ci modul în care aplicația va funcționa cu ele. Dacă trebuie să primească date diferite în moduri diferite sau aceleași date în moduri diferite, trebuie să le punem într-un mod convenabil pentru aplicație. În caz contrar, vom eșua în Full Scan și Cassandra nu ne va oferi niciun avantaj.

Denormalizarea datelor este norma. Uităm de formele normale, nu mai avem baze de date relaționale. Dacă punem ceva jos de 100 de ori, se va întinde de 100 de ori. Este încă mai ieftin decât oprirea.

Selectăm cheile pentru partiționare, astfel încât acestea să fie distribuite normal. Nu vrem ca hash-ul cheilor noastre să se încadreze într-un interval restrâns. Adică anul nașterii din exemplul de mai sus este un exemplu prost. Mai exact, este bine dacă utilizatorii noștri sunt repartizați în mod normal pe an de naștere, și rău dacă vorbim de elevi de clasa a V-a - compartimentarea acolo nu va fi foarte bună.

Sortarea este selectată o dată în etapa de creare a cheii de clusterizare. Dacă trebuie schimbat, va trebui să ne actualizăm tabelul cu o cheie diferită.

Și cel mai important lucru: dacă trebuie să recuperăm aceleași date în 100 de moduri diferite, atunci vom avea 100 de tabele diferite.

Sursa: www.habr.com

Adauga un comentariu