Cassandra. Hoe om nie te sterf as jy net Oracle ken nie

Haai Habr.

My naam is Misha Butrimov, ek wil jou 'n bietjie oor Cassandra vertel. My storie sal nuttig wees vir diegene wat nog nooit NoSQL-databasisse teëgekom het nie - dit het baie implementeringskenmerke en slaggate waarvan u moet weet. En as jy niks anders as Oracle of enige ander relasionele databasis gesien het nie, sal hierdie dinge jou lewe red.

Wat is so goed omtrent Cassandra? Dit is 'n NoSQL-databasis wat ontwerp is sonder 'n enkele punt van mislukking wat goed skaal. As jy 'n paar teragrepe vir een of ander databasis moet byvoeg, voeg jy eenvoudig nodusse by die ring. Brei dit uit na 'n ander datasentrum? Voeg nodusse by die groepering. Verhoog verwerkte RPS? Voeg nodusse by die groepering. Dit werk ook in die teenoorgestelde rigting.

Cassandra. Hoe om nie te sterf as jy net Oracle ken nie

Waarmee is sy nog goed? Dit gaan oor die hantering van baie versoeke. Maar hoeveel is baie? 10, 20, 30, 40 duisend versoeke per sekonde is nie veel nie. 100 duisend versoeke per sekonde vir opname - ook. Daar is maatskappye wat gesê het dat hulle 2 miljoen versoeke per sekonde hou. Hulle sal dit seker moet glo.

En in beginsel het Cassandra een groot verskil van relasionele data - dit is glad nie soortgelyk aan hulle nie. En dit is baie belangrik om te onthou.

Nie alles wat dieselfde lyk werk dieselfde nie

Eenkeer het 'n kollega na my toe gekom en gevra: "Hier is 'n CQL Cassandra-navraagtaal, en dit het 'n uitgesoekte stelling, dit het waar, dit het en. Ek skryf briewe en dit werk nie. Hoekom?". Om Cassandra soos 'n verhoudingsdatabasis te behandel, is die perfekte manier om gewelddadige selfmoord te pleeg. En ek bevorder dit nie, dit is verbode in Rusland. Jy sal net iets verkeerd ontwerp.

’n Kliënt kom byvoorbeeld na ons toe en sê: “Kom ons bou ’n databasis vir TV-reekse, of ’n databasis vir ’n reseptegids. Ons sal kosgeregte daar hê of ’n lys van TV-reekse en akteurs daarin.” Ons sê blymoedig: “Kom ons gaan!” Stuur net twee grepe, 'n paar tekens en jy is klaar, alles sal baie vinnig en betroubaar werk. En alles is reg totdat die klante kom en sê dat huisvrouens ook die teenoorgestelde probleem oplos: hulle het 'n lys produkte, en hulle wil weet watter gereg hulle wil kook. Jy is dood.

Dit is omdat Cassandra 'n hibriede databasis is: dit verskaf terselfdertyd 'n sleutelwaarde en stoor data in wye kolomme. In Java of Kotlin kan dit soos volg beskryf word:

Map<RowKey, SortedMap<ColumnKey, ColumnValue>>

Dit wil sê 'n kaart wat ook 'n gesorteerde kaart bevat. Die eerste sleutel tot hierdie kaart is die ry sleutel of partisie sleutel - die partisie sleutel. Die tweede sleutel, wat die sleutel tot 'n reeds gesorteerde kaart is, is die Clustering-sleutel.

Om die verspreiding van die databasis te illustreer, kom ons teken drie nodusse. Nou moet jy verstaan ​​hoe om die data in nodusse te ontbind. Want as ons alles in een druk (terloops, daar kan duisend, tweeduisend, vyf wees – soveel as wat jy wil), gaan dit nie eintlik oor verspreiding nie. Daarom het ons 'n wiskundige funksie nodig wat 'n getal sal teruggee. Net 'n nommer, 'n lang int wat in een of ander reeks sal val. En ons sal een nodus hê wat verantwoordelik is vir een reeks, die tweede vir die tweede, die nde een vir die nde.

Cassandra. Hoe om nie te sterf as jy net Oracle ken nie

Hierdie nommer word geneem met behulp van 'n hash-funksie, wat toegepas word op wat ons die partisiesleutel noem. Dit is die kolom wat in die Primêre sleutel-aanwysing gespesifiseer word, en dit is die kolom wat die eerste en mees basiese sleutel van die kaart sal wees. Dit bepaal watter nodus watter data sal ontvang. 'n Tabel word in Cassandra geskep met byna dieselfde sintaksis as in SQL:

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

)

Die Primêre sleutel in hierdie geval bestaan ​​uit een kolom, en dit is ook die partisiesleutel.

Hoe sal ons gebruikers presteer? Sommige sal na een nodus gaan, sommige na 'n ander, en sommige na 'n derde. Die resultaat is 'n gewone hash-tabel, ook bekend as 'n kaart, ook bekend as 'n woordeboek in Python, of 'n eenvoudige Sleutelwaardestruktuur waaruit ons al die waardes kan lees, lees en skryf volgens sleutel.

Cassandra. Hoe om nie te sterf as jy net Oracle ken nie

Kies: wanneer toelaat dat filter verander in volledige skandering, of wat om nie te doen nie

Kom ons skryf 'n paar uitgesoekte stellings: select * from users where, userid = . Dit blyk soos in Oracle: ons skryf kies, spesifiseer die voorwaardes en alles werk, gebruikers kry dit. Maar as jy byvoorbeeld 'n gebruiker met 'n sekere geboortejaar kies, kla Cassandra dat hy nie aan die versoek kan voldoen nie. Omdat sy glad niks weet van hoe ons data oor die geboortejaar versprei nie - sy het net een kolom wat as 'n sleutel aangedui word. Dan sê sy: “Goed, ek kan nog aan hierdie versoek voldoen. Voeg toelaat filtering by." Ons voeg die richtlijn by, alles werk. En op hierdie oomblik gebeur iets verskrikliks.

As ons op toetsdata hardloop, is alles in orde. En wanneer jy 'n navraag in produksie uitvoer, waar ons byvoorbeeld 4 miljoen rekords het, dan is alles nie baie goed vir ons nie. Omdat laat filtering 'n opdrag is wat Cassandra in staat stel om al die data van hierdie tabel vanaf alle nodusse, alle datasentrums (as daar baie van hulle in hierdie groepie is) te versamel en dit dan eers te filtreer. Dit is 'n analoog van Full Scan, en byna niemand is verheug daaroor nie.

As ons net gebruikers per ID nodig gehad het, sou ons goed daarmee gaan. Maar soms moet ons ander navrae skryf en ander beperkings op die keuse stel. Daarom onthou ons: dit is alles 'n kaart wat 'n partisiesleutel het, maar binne dit is 'n gesorteerde kaart.

En sy het ook 'n sleutel, wat ons die Clustering Key noem. Hierdie sleutel, wat op sy beurt bestaan ​​uit die kolomme wat ons kies, met behulp waarvan Cassandra verstaan ​​hoe sy data fisies gesorteer word en op elke nodus geleë sal wees. Dit wil sê, vir een of ander partisiesleutel sal die Clustering-sleutel jou presies vertel hoe om die data in hierdie boom te druk, watter plek dit daar sal inneem.

Dit is regtig 'n boom, 'n vergelyker word eenvoudig daar genoem, waarna ons 'n sekere stel kolomme in die vorm van 'n voorwerp deurgee, en dit word ook as 'n lys kolomme gespesifiseer.

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

Gee aandag aan die primêre sleutel riglyn; sy eerste argument (in ons geval, die jaar) is altyd partisie sleutel. Dit kan uit een of meer kolomme bestaan, dit maak nie saak nie. As daar verskeie kolomme is, moet dit weer tussen hakies verwyder word sodat die taalvoorverwerker verstaan ​​dat dit die Primêre sleutel is, en daaragter is al die ander kolomme die Clustering-sleutel. In hierdie geval sal hulle in die vergelyker oorgedra word in die volgorde waarin hulle verskyn. Dit wil sê, die eerste kolom is meer betekenisvol, die tweede is minder betekenisvol, ensovoorts. Hoe ons skryf, is byvoorbeeld gelyk aan velde vir dataklasse: ons lys die velde, en vir hulle skryf ons watter is groter en watter is kleiner. In Cassandra is dit relatief gesproke die velde van die dataklas, waarop die gelykes wat daarvoor geskryf is, toegepas sal word.

Ons stel sortering en stel beperkings op

Jy moet onthou dat die sorteervolgorde (dalend, stygend, wat ook al) gestel word op dieselfde oomblik wanneer die sleutel geskep word, en dit kan nie later verander word nie. Dit bepaal fisies hoe die data gesorteer sal word en hoe dit gestoor sal word. As jy die groeperingsleutel of sorteervolgorde moet verander, sal jy 'n nuwe tabel moet skep en data daarin moet oordra. Dit sal nie werk met 'n bestaande een nie.

Cassandra. Hoe om nie te sterf as jy net Oracle ken nie

Ons het ons tafel gevul met gebruikers en gesien dat hulle in 'n ring val, eers volgens geboortejaar, en toe binne op elke nodus volgens salaris en gebruikers-ID. Nou kan ons kies deur beperkings op te stel.

Ons werkende een verskyn weer where, and, en ons kry gebruikers, en alles is weer reg. Maar as ons probeer om slegs 'n deel van die Clustering-sleutel te gebruik, en 'n minder betekenisvolle een, dan sal Cassandra dadelik kla dat dit nie die plek op ons kaart kan vind waar hierdie voorwerp, wat hierdie velde vir die nulvergelyker het, en hierdie een dit was net gestel , - waar hy lê. Ek sal al die data van hierdie nodus weer moet optrek en dit filter. En dit is 'n analoog van Full Scan binne 'n nodus, dit is sleg.

In enige onduidelike situasie, skep 'n nuwe tabel

As ons gebruikers wil kan teiken volgens ID, of volgens ouderdom, of volgens salaris, wat moet ons doen? Niks nie. Gebruik net twee tafels. As jy gebruikers op drie verskillende maniere moet bereik, sal daar drie tabelle wees. Die dae toe ons spasie op die skroef gespaar het, is verby. Dit is die goedkoopste hulpbron. Dit kos baie minder as reaksietyd, wat nadelig vir die gebruiker kan wees. Dit is baie aangenamer vir die gebruiker om iets in 'n sekonde te ontvang as in 10 minute.

Ons verhandel onnodige spasie en gedenormaliseerde data vir die vermoë om goed te skaal en betroubaar te funksioneer. Trouens, 'n groepering wat uit drie datasentrums bestaan, wat elk vyf nodusse het, met 'n aanvaarbare vlak van databewaring (wanneer niks verlore gaan nie), is in staat om die dood van een datasentrum heeltemal te oorleef. En nog twee nodusse in elk van die oorblywende twee. En eers hierna begin die probleme. Dit is 'n redelik goeie oortolligheid, dit is 'n paar ekstra SSD-aandrywers en verwerkers werd. Daarom, om Cassandra te gebruik, wat nooit SQL is nie, waarin daar geen verhoudings, vreemde sleutels is nie, moet jy eenvoudige reëls ken.

Ons ontwerp alles volgens jou versoek. Die belangrikste ding is nie die data nie, maar hoe die toepassing daarmee gaan werk. As dit verskillende data op verskillende maniere of dieselfde data op verskillende maniere moet ontvang, moet ons dit op 'n manier stel wat gerieflik is vir die toepassing. Andersins sal ons misluk in Volledige skandering en Cassandra sal ons geen voordeel gee nie.

Denormalisering van data is die norm. Ons vergeet van normale vorms, ons het nie meer relasionele databasisse nie. As ons iets 100 keer neersit, sal dit 100 keer lê. Dit is steeds goedkoper as om te stop.

Ons kies die sleutels vir partisionering sodat hulle normaal versprei word. Ons wil nie hê die hash van ons sleutels moet in een nou reeks val nie. Dit wil sê, die geboortejaar in die voorbeeld hierbo is 'n slegte voorbeeld. Meer presies, dit is goed as ons gebruikers normaalweg volgens geboortejaar versprei word, en sleg as ons van graad 5-leerlinge praat - die verdeling daar sal nie baie goed wees nie.

Sortering word een keer gekies tydens die skepping van groeperingsleutels. As dit verander moet word, sal ons ons tabel met 'n ander sleutel moet opdateer.

En die belangrikste ding: as ons dieselfde data op 100 verskillende maniere moet herwin, sal ons 100 verskillende tabelle hê.

Bron: will.com

Voeg 'n opmerking