Cassandra. Hvordan ikke at dø, hvis du kun kender Oracle

Hej Habr.

Mit navn er Misha Butrimov, jeg vil gerne fortælle dig lidt om Cassandra. Min historie vil være nyttig for dem, der aldrig har stødt på NoSQL-databaser - den har en masse implementeringsfunktioner og faldgruber, som du skal kende til. Og hvis du ikke har set andet end Oracle eller en anden relationel database, vil disse ting redde dit liv.

Hvad er så godt ved Cassandra? Det er en NoSQL-database designet uden et enkelt fejlpunkt, der skaleres godt. Hvis du har brug for at tilføje et par terabyte til en eller anden database, tilføjer du blot noder til ringen. Vil du udvide det til et andet datacenter? Tilføj noder til klyngen. Øge behandlet RPS? Tilføj noder til klyngen. Det virker også i den modsatte retning.

Cassandra. Hvordan ikke at dø, hvis du kun kender Oracle

Hvad er hun ellers god til? Det handler om at håndtere en masse forespørgsler. Men hvor meget er meget? 10, 20, 30, 40 tusinde anmodninger i sekundet er ikke meget. 100 forespørgsler i sekundet til optagelse - også. Der er virksomheder, der sagde, at de beholder 2 millioner anmodninger i sekundet. De skal nok tro på det.

Og i princippet har Cassandra én stor forskel fra relationelle data – det ligner dem slet ikke. Og dette er meget vigtigt at huske.

Ikke alt, der ser ens ud, fungerer ens

Engang kom en kollega til mig og spurgte: "Her er et CQL Cassandra-forespørgselssprog, og det har en select-sætning, det har hvor, det har og. Jeg skriver breve, og det virker ikke. Hvorfor?". At behandle Cassandra som en relationel database er den perfekte måde at begå voldeligt selvmord på. Og jeg promoverer det ikke, det er forbudt i Rusland. Du vil bare designe noget forkert.

For eksempel kommer en kunde til os og siger: ”Lad os bygge en database til tv-serier, eller en database til et opskriftsmappe. Vi vil have madretter der eller en liste over tv-serier og skuespillere i den.” Vi siger glædeligt: ​​"Lad os gå!" Bare send to bytes, et par tegn, og du er færdig, alt vil fungere meget hurtigt og pålideligt. Og alt er fint, indtil kunderne kommer og siger, at husmødre også løser det modsatte problem: De har en liste over produkter, og de vil vide, hvilken ret de vil lave. Du er død.

Dette skyldes, at Cassandra er en hybrid database: den giver samtidig en nøgleværdi og gemmer data i brede kolonner. I Java eller Kotlin kan det beskrives sådan:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

Det vil sige et kort, der også indeholder et sorteret kort. Den første nøgle til dette kort er rækketasten eller partitionsnøglen - partitioneringsnøglen. Den anden nøgle, som er nøglen til et allerede sorteret kort, er Clustering-nøglen.

For at illustrere fordelingen af ​​databasen, lad os tegne tre noder. Nu skal du forstå, hvordan du dekomponerer dataene i noder. For hvis vi propper alt sammen i én (der kan i øvrigt være tusind, to tusinde, fem – lige så mange du vil), så handler det ikke rigtigt om distribution. Derfor har vi brug for en matematisk funktion, der vil returnere et tal. Bare et tal, et langt int, der falder inden for et eller andet område. Og vi vil have en node ansvarlig for et område, den anden for den anden, den n'te for den n'te.

Cassandra. Hvordan ikke at dø, hvis du kun kender Oracle

Dette nummer tages ved hjælp af en hash-funktion, som anvendes på det, vi kalder partitionsnøglen. Dette er den kolonne, der er specificeret i Primary Key-direktivet, og dette er den kolonne, der vil være den første og mest grundlæggende nøgle på kortet. Det bestemmer, hvilken node der modtager hvilke data. En tabel oprettes i Cassandra med næsten samme syntaks som i SQL:

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

)

Den primære nøgle i dette tilfælde består af én kolonne, og det er også partitioneringsnøglen.

Hvordan vil vores brugere præstere? Nogle vil gå til en node, nogle til en anden og nogle til en tredje. Resultatet er en almindelig hash-tabel, også kendt som et kort, også kendt som en ordbog i Python, eller en simpel nøgleværdistruktur, hvorfra vi kan læse alle værdierne, læse og skrive efter nøgle.

Cassandra. Hvordan ikke at dø, hvis du kun kender Oracle

Vælg: når tillad filtrering bliver til fuld scanning, eller hvad du ikke skal gøre

Lad os skrive et udvalgt udsagn: select * from users where, userid = . Det viser sig som i Oracle: vi skriver select, specificerer betingelserne og alt fungerer, brugerne får det. Men hvis du for eksempel vælger en bruger med et bestemt fødselsår, klager Cassandra over, at den ikke kan opfylde anmodningen. Fordi hun ikke ved noget som helst om, hvordan vi fordeler data om fødselsåret - hun har kun én kolonne angivet som en nøgle. Så siger hun: "Okay, jeg kan stadig opfylde denne anmodning. Tilføj tillad filtrering." Vi tilføjer direktivet, alt virker. Og i dette øjeblik sker der noget forfærdeligt.

Når vi kører på testdata, er alt i orden. Og når man udfører en forespørgsel i produktionen, hvor vi for eksempel har 4 millioner poster, så er alt ikke særlig godt for os. Fordi tillad filtrering er et direktiv, der tillader Cassandra at indsamle alle data fra denne tabel fra alle noder, alle datacentre (hvis der er mange af dem i denne klynge), og først derefter filtrere det. Dette er en analog af Full Scan, og næppe nogen er glade for det.

Hvis vi kun havde brug for brugere efter ID, ville vi have det fint med dette. Men nogle gange er vi nødt til at skrive andre forespørgsler og pålægge andre begrænsninger for udvælgelsen. Lad os derfor huske: dette er alt sammen et kort, der har en partitioneringsnøgle, men indeni det er et sorteret kort.

Og hun har også en nøgle, som vi kalder Clustering Key. Denne nøgle, som igen består af de kolonner, som vi vælger, ved hjælp af hvilken Cassandra forstår, hvordan dens data er fysisk sorteret og vil blive placeret på hver node. Det vil sige, for nogle partitionsnøgler vil Clustering-nøglen fortælle dig præcis, hvordan du skal skubbe dataene ind i dette træ, hvilken plads de vil tage der.

Dette er virkelig et træ, en komparator kaldes der simpelthen, hvortil vi sender et bestemt sæt kolonner i form af et objekt, og det er også angivet som en liste over kolonner.

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

Vær opmærksom på Primary Key-direktivet; dets første argument (i vores tilfælde årstal) er altid Partitionsnøgle. Det kan bestå af en eller flere kolonner, det er lige meget. Hvis der er flere kolonner, skal det fjernes i parentes igen, så sprogforbehandleren forstår, at dette er den primære nøgle, og bagved er alle de andre kolonner Clustering-nøglen. I dette tilfælde vil de blive transmitteret i komparatoren i den rækkefølge, de vises. Det vil sige, at den første kolonne er mere betydningsfuld, den anden er mindre betydningsfuld, og så videre. Hvordan vi skriver, er f.eks. lig med felter for dataklasser: Vi lister felterne, og for dem skriver vi, hvilke der er større og hvilke der er mindre. I Cassandra er disse, relativt set, dataklassens felter, hvorpå de ligninger, der er skrevet for den, vil blive anvendt.

Vi sætter sortering og pålægger restriktioner

Du skal huske, at sorteringsrækkefølgen (faldende, stigende, uanset hvad) er indstillet på samme tidspunkt, når nøglen oprettes, og den kan ikke ændres senere. Det bestemmer fysisk, hvordan dataene vil blive sorteret, og hvordan de vil blive opbevaret. Hvis du har brug for at ændre klyngingsnøglen eller sorteringsrækkefølgen, skal du oprette en ny tabel og overføre data til den. Dette vil ikke fungere med en eksisterende.

Cassandra. Hvordan ikke at dø, hvis du kun kender Oracle

Vi fyldte vores bord med brugere og så, at de faldt i en ring, først efter fødselsår, og derefter inde på hver node efter løn og bruger-id. Nu kan vi vælge ved at pålægge begrænsninger.

Vores arbejde dukker op igen where, and, og vi får brugere, og alt er fint igen. Men hvis vi prøver kun at bruge en del af Clustering-nøglen, og en mindre betydningsfuld, så vil Cassandra straks klage over, at den ikke kan finde stedet på vores kort, hvor dette objekt, som har disse felter til nul-komparatoren, og denne ene det var lige sat , - hvor han ligger. Jeg bliver nødt til at trække alle data op fra denne node igen og filtrere dem. Og dette er en analog af fuld scanning i en node, det er dårligt.

I enhver uklar situation skal du oprette en ny tabel

Hvis vi vil være i stand til at målrette brugere efter ID, alder eller løn, hvad skal vi så gøre? Ikke noget. Brug blot to borde. Skal du nå ud til brugerne på tre forskellige måder, vil der være tre borde. De dage, hvor vi sparede plads på skruen, er forbi. Dette er den billigste ressource. Det koster meget mindre end svartid, hvilket kan være til skade for brugeren. Det er meget mere behageligt for brugeren at modtage noget på et sekund end på 10 minutter.

Vi bytter unødvendig plads og denormaliserede data for evnen til at skalere godt og fungere pålideligt. Faktisk er en klynge, der består af tre datacentre, som hver har fem noder, med et acceptabelt niveau af databevarelse (når intet går tabt), i stand til at overleve et datacenters død fuldstændigt. Og yderligere to noder i hver af de resterende to. Og først efter dette begynder problemerne. Dette er en ret god redundans, den er et par ekstra SSD-drev og processorer værd. Derfor, for at bruge Cassandra, som aldrig er SQL, hvor der ikke er nogen relationer, fremmednøgler, skal du kende simple regler.

Vi designer alt efter dit ønske. Det vigtigste er ikke dataene, men hvordan applikationen kommer til at arbejde med dem. Hvis det skal modtage forskellige data på forskellige måder eller de samme data på forskellige måder, skal vi sætte det på en måde, der er praktisk for applikationen. Ellers vil vi fejle i fuld scanning, og Cassandra vil ikke give os nogen fordel.

Denormalisering af data er normen. Vi glemmer normale former, vi har ikke længere relationelle databaser. Hvis vi lægger noget ned 100 gange, vil det ligge 100 gange. Det er stadig billigere end at stoppe.

Vi vælger nøglerne til partitionering, så de fordeles normalt. Vi ønsker ikke, at vores nøgles hash falder inden for et snævert område. Det vil sige, at fødselsåret i eksemplet ovenfor er et dårligt eksempel. Mere præcist er det godt, hvis vores brugere er normalfordelt på fødselsår, og dårligt, hvis vi taler om 5. klasses elever – opdelingen der bliver ikke særlig god.

Sortering vælges én gang ved oprettelse af klyngenøgle. Hvis det skal ændres, bliver vi nødt til at opdatere vores tabel med en anden nøgle.

Og det vigtigste: Hvis vi skal hente de samme data på 100 forskellige måder, så vil vi have 100 forskellige tabeller.

Kilde: www.habr.com

Tilføj en kommentar