Cassandra Indexing: the Good, The Bad and The Ugly

în cadrul NoSQL, operațiunile de indexare, preluare și căutare a informațiilor sunt strâns legate de mecanismele fizice de stocare. Este important să ne amintim că rândurile sunt stocate pe gazde, dar un singur rând este stocat pe o singură gazdă. (cu replici) familiile de coloane sunt stocate în ordine sortată, ceea ce face interogarea unui set de coloane eficiente (cu condiția să se întinde rânduri).

Cel Rău : Partiționare

unul dintre lucrurile dificile cu care să te obișnuiești la început este că, fără niciun index, interogările care se întind pe rânduri pot fi (foarte) rele. Cu toate acestea, gândindu-ne la modelul nostru de stocare, acest lucru nu este surprinzător. Strategia pe care Cassandra o folosește pentru a distribui rândurile între gazde se numește partiționare.

partiționarea este actul de sculptură în sus gama de rowkeys atribuindu-le în” token ring”, care atribuie, de asemenea, responsabilitatea pentru un segment (adică partiție) din gama rowkey pentru fiecare gazdă. Probabil ați văzut acest lucru când ați inițializat clusterul cu un „jeton”. Tokenul oferă gazdei o locație de-a lungul inelului token, care atribuie responsabilitatea pentru o secțiune a intervalului token. Partiționarea este actul de mapare a cheii de rând în intervalul de Jetoane.

există doi partiționari primari: aleatoriu și păstrarea ordinii. Ele sunt numite în mod corespunzător. RandomPartitioner hashes rowkeys în jetoane. Cu RandomPartitioner, jetonul este un hash al rowkey. Acest lucru face o treabă bună de distribuire uniformă a datelor dvs. într-un set de noduri, dar face interogarea unei game de spațiu rowkey incredibil de dificilă. De la doar o valoare” start rowkey „și o valoare” end rowkey”, Cassandra nu poate determina ce interval de spațiu token aveți nevoie. În esență, trebuie să efectueze o” scanare a tabelului „pentru a răspunde la interogare, iar o” scanare a tabelului ” în Cassandra este rea, deoarece trebuie să meargă la fiecare mașină (cel mai probabil toate mașinile dacă aveți o funcție hash bună) pentru a răspunde la interogare.

acum, la costul mare al distribuției uniforme a datelor, puteți utiliza OrderPreservingPartitioner (OPP). Eu sunt* nu * în jos cu OPP. OPP păstrează ordinea, deoarece traduce rowkeys în jetoane. Acum, având în vedere o valoare rowkey start și o valoare rowkey end, Cassandra *poate* determina exact ce gazde au datele pe care le căutați. Se calculează valoarea de pornire la un jeton valoarea finală la un jeton, și pur și simplu selectează și returnează totul în între. Dar, prin păstrarea ordinii, cu excepția cazului în care rowkeys sunt distribuite uniform în spațiu, jetoanele dvs. nu vor fi nici ele și veți obține un cluster dezechilibrat, ceea ce crește foarte mult costul configurării și Administrării clusterului. (nu merita)

bunul: indicii secundari

Cassandra oferă un mecanism nativ de indexare în indicii secundari. Indicii secundari lucrează în afara valorilor coloanelor. Declarați un index secundar pe o familie coloană. Datastax are o documentație bună privind utilizarea. Sub capotă, Cassandra menține o” familie de coloane ascunse ” ca index. (A se vedea prezentarea Ed Anuff pentru specificul) deoarece Cassandra nu menține informații valoare coloană în orice nod, și indicii secundari sunt pe coloane valoare (mai degrabă decât rowkeys), o interogare încă trebuie să fie trimis la toate nodurile. În plus, indicii secundari nu sunt recomandați pentru seturile de cardinalitate ridicată. Nu m-am uitat încă, dar presupun că acest lucru se datorează modelului de date utilizat în „familia coloanei ascunse”. Dacă familia de coloane ascunse stochează un rând pe valoare unică (cu chei de rând ca coloane), atunci ar însemna scanarea rândurilor pentru a determina dacă acestea se află în intervalul din interogare.
din prezentarea lui Ed:

  • nu este recomandat pentru valori cardinale ridicate (de exemplu,marcaje temporale,date de naștere,cuvinte cheie etc.)
  • necesită cel puțin o comparație egalitate într-o interogare-nu mare pentru mai puțin de/mai mare decât/gama interogări
  • Nesortate-rezultatele sunt în ordine simbolică, nu interogare valoare ordine
  • limitat la căutare pe tipuri de date, Cassandra înțelege nativ

cu toate acestea, indicii secundari funcționează din cutie și am avut un succes bun folosindu-i pe valori simple.

urâtul: Do-It-Yourself (DIY) / rânduri largi

acum, frumusețea este în ochii privitorului. Unul dintre lucrurile frumoase despre NoSQL este simplitatea. Construcțiile sunt simple: spații de chei, familii de coloane, rânduri și coloane. Păstrarea simplu cu toate acestea înseamnă, uneori, aveți nevoie pentru a lua lucrurile în propriile mâini.

acesta este cazul indexurilor cu rânduri largi. Utilizand modelul de stocare Cassandra, ușor de a construi propriile indici în cazul în care fiecare rând-cheie devine o coloană în index. Acest lucru este uneori greu pentru a obține capul în jurul valorii de, dar să ne imaginăm avem un caz prin care dorim să selectăm toți utilizatorii într-un cod poștal. Familia principală de coloane utilizatori este tastată pe ID-ul utilizatorului, codul poștal este o coloană pe fiecare rând de utilizator. Am putea folosi indici secundari, dar există destul de multe coduri poștale. În schimb, am putea menține o familie de coloane cu un singur rând numit „idx_zipcode”. Am putea scrie apoi coloane în acest rând al formularului „zipcode_userid”. Deoarece coloanele sunt stocate în ordine sortată, este rapid să interogați toate coloanele care încep cu „18964” (de exemplu, am putea folosi 18964_ și 18964_zzzzzz ca valori de început și sfârșit).

un dezavantaj evident al acestei abordări este că rândurile sunt autonome pe o gazdă. (din nou, cu excepția replicilor) aceasta înseamnă că toate interogările vor atinge un singur nod. Nu am găsit încă un răspuns bun pentru asta.

în plus, și IMHO, cea mai urâtă parte a indexării DIY pe rânduri largi este din perspectiva clientului. În implementarea noastră, am făcut tot posibilul pentru a fi agnostici lingvistici din partea clientului, permițând oamenilor să aleagă cel mai bun instrument pentru job pentru a interacționa cu datele din Cassandra. Cu această mentalitate, indicii DIY prezintă unele probleme. Rândurile largi folosesc adesea chei compozite (imaginați-vă dacă ați avea un idx_state_zip, care vă va permite să interogați după stat, apoi zip). Deși există suport „nativ” pentru cheile compozite, toate bibliotecile client implementează propria versiune a acestora (Hector, Astyanax și Thrift). Aceasta înseamnă că clientul care trebuie să interogheze datele trebuie să aibă logica adăugată pentru a interoga mai întâi indexul și, în plus, toți clienții trebuie să construiască cheia compusă în același mod.

A Face Mai Bine…

tocmai din acest motiv, am decis să lansăm două proiecte open source care ajută la împingerea acestei logici pe partea de server. Primul proiect este Cassandra-Triggers. Acest lucru vă permite să atașați activități asincrone pentru a scrie în Cassandra. (o astfel de activitate ar putea fi indexarea) am lansat, de asemenea, Cassandra-indexare. Acest lucru este fierbinte de pe prese și este încă în fază incipientă (de exemplu, acceptă doar UT8Types în index), dar intenția este de a oferi un mecanism generic de server care indexează datele așa cum este scris la Cassandra. Folosind aceeași tehnică server-side am folosit în Cassandra-indexare, pur și simplu configurați coloanele pe care doriți indexate, iar codul AOP face restul pe măsură ce scrie la CF țintă. Ca întotdeauna, întrebările, comentariile și gândurile sunt binevenite. (mai ales dacă sunt în afara bazei undeva)

Lasă un răspuns

Adresa ta de email nu va fi publicată.