Sistemul de Gestiune pentru Baze de Date Distribuite HBase

HBase este o bază de date distribuită, orientată pe coloane, construită peste HDFS, fiind utilizată în cazul aplicaţiilor Hadoop care necesită operaţii de citire / scriere aleatoare în seturi de date foarte mari. Este scris în Java şi poate fi accesat atât prin intermediul unui client propriu cât şi prin intermediul unui API foarte simplu.

Cele mai multe sisteme de baze de date relaţionale sunt orientate pe rânduri, în sensul că reţin informaţiile contiguu per înregistrare. În sistemele de baze de date orientate pe coloane, informaţiile sunt reţinute contiguu per atribut, în ideea că pentru anumite interogări nu sunt necesare toate valorile (în special pentru bazele de date analitice). De asemenea, este redus traficul generat în cazul operaţiilor de intrare/ieşire şi în plus, datorită gradului mic de variaţie între înregistrările aceluiaşi atribut, se poate realiza o compresie mai bună, comparativ cu situaţia în care sunt reţinute împreună date eterogene (cum se întâmplă în cazul rândurilor). HBase este o bază de date orientată pe coloane în sensul că utilizează un format de stocare pe disc pe bază de coloane, oferind acces rapid la o celulă de date (sau grup de celule secvenţiale) pe baza unei chei. De asemenea, este foarte util pentru procesări analitice, care presupun scanarea unei game mari de înregistrări sau chiar a întregii tabele.

Cu toate că există nenumărate strategii şi implementări pentru stocarea bazelor de date şi obţinerea informaţiilor din cadrul acestora, cele mai multe (în special derivate din categoria bazelor de date relaţionale) nu sunt scalabile în cazul în care dimensiunea datelor este foarte mare (scalabilitatea se referă la faptul că problema nu poate fi rezolvată doar prin adăugarea de alte resurse, cum ar fi discuri sau unităţi de procesare). Deşi au fost găsite soluţii pentru partiţionare şi replicare, acestea sunt extensii ale unui produs care nu a fost proiectat iniţial pentru astfel de operaţii, astfel încât sunt dificil de întreţinut. Totodată, toate restricţiile pe care le presupune modelul de date relaţional (interogări complexe conţinând joncţiuni, constrângeri de integritate de tip cheie străină, triggere şi vizualizări) – inclusiv cele 12 reguli ale lui Codd - vor implica resurse extrem de costisitoare pentru a putea fi întrunite.

În cazul bazelor de date relaţionale, aşteptările şi zonele de blocare (eng. deadlocks) cresc non-liniar cu tranzacţiile (de ordinul n2) respectiv cu nivelul de concurenţă (de ordinul n3-n5). Diferite forme de partiţionare (eng. sharding) sunt de regulă nepractice, deoarece trebuie realizate la nivelul aplicaţiei, implicând prodceduri complexe, care necesită resurse destul de scumpe.

Din acest punct de vedere, HBase a fost creat pentru a preîntimpina problema scalabilităţii în situaţia creşterii dimensiunii informaţiilor care trebuie stocate prin adăugarea de noduri. Nefiind o bază de date relaţională şi nefiind bazată pe SQL, este capabilă să ofere găzduirea unor tabele de dimensiuni mari, populate în mod inegal, pe clustere formate din maşini larg disponibile în comerţ, fără performanţe deosebite.

Un principiu de la care s-a pornit în proiectarea acestui tip de bază de date este Denormalizare, Duplicare şi Chei Inteligente (presucrtat DDI – eng. Denormalization, Duplication and Intelligent Keys). Astfel, denormalizarea este realizată prin duplicarea datelor, astfel încât pentru operaţiile de citire să nu fie necesară agregarea, acestea realizându-se într-un timp acceptabil fără a se mai realiza şi alte procesări. Totodată, utilizarea cheilor inteligente oferă control asupra nivelului de granularitate cu privire la modul şi locul în care sunt stocate datele. O astfel de proiectare a schemei conduce la scalabilitate în privinţa cantităţii de informaţie ce poate fi stocată cu păstrarea performanţelor legate de operaţiile de scriere şi de citire. Comparativ cu sistemele de baze de date relaţionale, API-ul pe care îl pune la dispoziţie HBase este foarte simplu şi prin urmare, limitat. Astfel, nu trebuie folosit pentru aplicaţii tranzacţionale care utilizează analize relaţionale (de tipul group by, join). De asemenea, nu funcţionează optim pentrul accesul bazat pe căutare de text.

HBase reprezintă însă o soluţie pentru seturi de informaţii de dimensiuni foarte mari (de ordinul milioanelor şi miliardelor de înregistrări) sau pentru aplicaţii ce utilizează date care sunt accesate de foarte mulţi clienţi (cererile şi răspunsurile generate ca urmare a acestei interacţiuni implică un volum de date foarte mare). Totodată, funcţionează optim în cazul unor scheme variabile, unde structura înregistrărilor diferă (datorită unor atribute care pot să existe sau nu).

În cazul în care datele utilizate sunt de dimensiuni foarte mici, înregistrările vor fi stocate pe un singur nod, astfel încât restul clusterului nu va mai fi utilizat pentru nimic.

Pentru a implementa toate aceste funcţionalităţi, suportul hardware trebuie să fie corespunzător, acest sistem de baze de date distribuit solicitând cel puţin cinci noduri corespunzătoare proceselor ce rulează în fundal. Altfel, configuraţia implicită (folosind un nivel de replicare 3) va avea performanţe destul de reduse. Ca regulă, HBase utilizează în mod intensiv capacitatea de procesare a nodurilor şi memoria acestora.

Proiectul HBase a fost pornit în 2006 de Chad Walters şi Jim Kellerman ca urmare a publicării articolului Bigtable: un sistem de stocare distribuit pentru date structurate, scris de mai mulţi cercetători de la Google. În 2007, Mike Cafarella avea deja o versiune funcţională, care a fost ulterior dezvoltată de Jim Kellerman. În acelaşi an, distribuţia HBase era integrată ca parte a Hadoop 0.15.0. În 2010, acesta a devenit un proiect de sine stătător al Apache, având clienţi precum Adobe, Facebook, Twitter, Meetup, Netflix precum şi unele grupuri ale Yahoo!.

În ceea ce priveşte arhitectura, există unele similitudini cu sistemele de baze de date tradiţionale, unitatea de bază fiind reprezentată de coloană, mai multe formând un rând care poate fi adresat în mod unic prin intermediul unei chei.

Fiind unică, cheia rândului poate fi comparată cu cheia primară din cazul bazelor de date relaţionale. Aceasta poate fi un vector de octeţi arbitrar şi nu trebuie să fie reprezentată într-un format care să poată fi înţeles de un utilizator uman. Astfel, se permite ca orice fel de informaţie (inclusiv structuri de date definite de utilizator) să fie folosită pe post de cheie a rândului. Totodată, HBase implementează şi specificarea de indecşi secundari.

Fiecare coloană poate avea mai multe versiuni, valorile distincte fiind conţinute într-o celulă distinctă. Rândurile sunt sortate lexicografic în funcţie de cheia rândului, comparaţiile realizându-se în acest caz în mod binar, octet cu octet, de la stânga la dreapta. Coloanele sunt grupate în familii, ceea ce permite crearea de limite (semantice sau tematice) între date, aplicându-se şi anumite caracteristici, cum ar fi compresia sau stocarea în memorie. Familiile de coloane trebuie specificate la crearea tabelei şi nu ar trebui schimbate prea frecvent, numărul lor trebuind să fie redus. Numele unei familii de coloane trebuie să constea din caractere care pot fi afişate, caracteristică distinctă faţă de alte nume sau valori.

Toate coloanele dintr-o familie sunt stocate împreună în cadrul aceluiaşi fişier de nivel scăzut, denumit HFile.

O coloană este referită ca familie:identificator, unde identificator este un şir arbitrar de octeţi. O familie poate avea oricât de multe coloane, neimpunându-se restricţii nici cu privire la valorile reţinute. Fiecare celulă poate avea o amprentă de timp care va fi inclusă implicit de sistem sau poate fi specificată explicit de utilizator, dacă doreşte să reţină mai multe versiuni ale unei valori, pe măsură ce se schimbă de-a lungul timpului. Vesiunile sunt ordonate descrescător în funcţie de amprenta de timp, permiţând obţinerea celei mai recente valori. Aceasta reprezintă o optimizare menită să favorizeze versiunile curente în detrimentul versiunilor istorice. Utilizatorul poate indica câte versiuni ale unei valori trebuie să fie reţinute. În plus, există suport pentru ştergerea predicatelor, permiţând reţinerea doar a valorilor dintr-o anumită perioadă. Valorile sunt şiruri de octeţi neinterpretaţi pe care îi va gestiona utilizatorul aplicaţiei.

Având în vedere faptul că modelul Bigtable (implementat de HBase) este definit ca o asociere multidimensională, pesistentă, distribuită şi împrăştiată, mecanismul de acces la o anumită valoare este dat de perechea mai multor caracteristici:

(Table, RowKey, Family, Column, Timestamp) → Value

sau, exprimată într-un stil mai asemănator limbajului de programare Java:

SortedMap<
    RowKey, List<
        SortedMap<
            Column, List<
                Value, Timestamp
            >
        >
    >
>

Aşadar, o tabela din HBase este o asociere ordonată pe baza cheii de rând (RowKey) a unei liste reprezentând familiile de coloane. La rândul ei, aceasta este tot o asociere ordonată pe baza numelui coloanei (Column), care conţine o listă a valorilor corespunzătoare (Value) în funcţie de amprenta de timp (Timestamp). Interesant este faptul că valorile din celule există în versiuni multiple şi unele coloane pot să fie scrise la momente diferite de timp. Prin intermediul API-ului se oferă o viziune coerentă a întregii tabele, fiind oferită cea mai recentă valoare a unei celule. Deşi datele sunt adăugate la momente diferite şi dispun de mai multe versiuni, utilizatorul va putea vedea o înregistrare ca o combinaţie a tuturor coloanelor, pentru fiecare selectându-se valoarea care asociază amprenta de timp cea mai recentă.

Există de asemenea posibilitatea de a accesa valorile având o anumită amprentă de timp (respectiv înainte sau după o amprentă de timp) sau chiar mai multe versiuni în cadrul unei singure interogări.

RowKey Timestamp Coloana “data”: Coloana “meta:”
“mimetype” “size”
row1 t3 “{
“name”:“lars”,
“address”:”…“
}”
“2323”
t6 “{
“name”:“lars”,
“address”:”…“
}”
t8 “application:json”
t9 “{
“name”:“lars”,
“address”:”…“
}”

În exemplu, este prezentată o tabelă HBase cu două familii de coloane: data (având coloanele name şi address) şi meta (având coloanele mimetype şi size). Deşi pentru înregistrarea (rândul) identificat de cheia row1 atributele (coloanele) au fost precizate la momente diferite de timp (t3, t6, t8, t9), pentru unele dintre ele existând mai multe versiuni, reprezentarea înregistrării este dată de valorile cele mai recente pentru fiecare dintre coloane (marcate corespunzător).

Accesul la un rând este realizat atomic şi include orice număr de coloane citite sau scrise. Nu se oferă nici un fel de garanţii cu privire la tranzacţiile care implică mai multe rânduri sau mai multe tabele. Această proprietate reprezintă un factor care contribuie la faptul că arhitectura HBase este strict consistentă, astfel că fiecare utilizator care citeşte sau scrie poate face presupuneri legate de siguranţa stării rândului respectiv. Un alt factor care contribuie la consistenţa arhitecturii este reprezentat de posibilitatea stocării mai multor versiuni identificate prin intermediul unor amprente de timp.

În HBase, unitatea de bază ce asigură scalabilitatea şi echilibrul încărcării este denumită regiune. O regiune este reprezentată de o colecţie contiguă de rânduri stocate împreună. În momentul când devin prea mari, sunt împărţite în mod automat de sistem (eng. auto-sharding). Alternativ, ele pot fi de asemenea concatenate pentru a le reduce numărul precum şi fişierele de stocare necesare. Regiunile sunt echivalentul partiţiilor pe baza intervalelor de valori folosite în cazul bazelor de date. Acestea pot fi repartizate pe mai multe maşini fizice, distribuind încărcarea şi astfel oferind scalabilitate.

Iniţial există o singură regiune pentru o tabelă şi pe măsură ce sunt adăugate date la ea, sistemul o monitorizează pentru a se asigura faptul că nu este depăşită limita maximă. Dacă această limită este depăşită, regiunea este împărţită în părţi egale, determinate prin intermediul cheii de rând.

Fiecare regiune este gestionată de un server de regiune (eng. regionserver), fiecare dintre aceste servere putând opera asupra mai multor regiuni concomitent. Numărul de regiuni care pot fi gestionate de un server de regiune este cuprins între 10 şi 1000, fiecare regiune putând avea o dimensiune cuprinsă între 1GB şi 2GB. Aceste valori pot fi modificate cu timpul, principiul de distribuire a regiunilor pe serverele aferente fiind determinat de posibilităţile de stocare şi de capacităţile de procesare ale acestora. Implementarea unui astfel de mecanism permite recuperarea în caz de eroare în momentul în care un server se opreşte din funcţionare din cauza unei erori şi asigură echilibrarea încărcării. Procesul de împărţire este de asemenea foarte rapid (aproape instantaneu) de vreme ce regiunile sunt citite din fişierele de stocare originale până la momentul în care sunt rescrise în alte fişiere de stocare în mod asincron.

În HBase, datele sunt reţinute în fişiere de stocare, denumite HFile, implementate ca asocieri persistente şi ordonate invariabil de la chei la valori. Acestea oferă un API pentru a accesa valori specifice şi pentru a scana o gamă de valori, dându-se o cheie de început şi o cheie de sfârşit. Intern, ele sunt reprezentate ca secvenţe de blocuri sufixate de un index. Dimensiunea implicită a unui bloc este de 64KB, dar aceasta poate fi configurată diferit în cazul în care este necesar. El este încărcat atunci când fişierul e deschis şi reţinut în memorie. Întrucât fiecare HFile dispune de un index de bloc, căutările pot fi realizate printr-o singură parcurgere a datelor pe disc. Astfel, blocul care ar putea conţine cheia solicitată este identificat printr-o căutare binară în indecşii aflaţi în memorie, după care este citit de pe disc pentru a se determina cheia propriu-zisă. De regulă, fişierele de stocare sunt reţinute în sistemul de fişiere distribuit HDFS, caracterizat prin scalabilitate, persistenţă şi replicabilitate, garantând că datele nu sunt niciodată pierdute prin reţinerea modificărilor în cadrul unui număr de maşini fizice.

În momentul în care informaţiile sunt actualizate, acestea sunt stocate într-un jurnal de date transmise (eng. commit log), denumit în HBase jurnal de scriere anticipată (WAL – eng. write-ahead log), după care sunt transferate în memorie. Odată ce datele din memorie au depăşit o valoare maximă, acestea sunt reţinute pe disc sub forma unui fişier HFile. Ulterior, intrările reţinute în jurnal pot fi şterse până la valorile care nu au fost încă stocate persistent. Concomitent cu stocarea informaţiilor pe disc, sistemul poate gestiona operaţiile de citire şi de scriere fără a fi constrâns să le blocheze. Acest comportament este obţinut prin faptul că datele din memorie sunt stocate pe disc în timp ce informaţiile care se doresc actualizate sunt transmise la o nouă zonă de memorie care este goală. Datele din aceste zone tampon sunt deja sortate prin cheile corespunzătoare fişierelor HFile de pe disc, astfel încât nu mai trebuie realizate şi alte procesări, optimizându-se astfel transferul unui volum mare de date. Fiind utilizate pentru a reţine împreună datele între care există o anumită legătură, aceste chei sunt de fapt proprietăţi de localizare. Fişierele conţin perechi ordonate (cheie, valoare) fiind optimizate pentru operaţii de bloc cum ar fi citirea şi scrierea secvenţială a acestor valori. Întrucât fişierele de stocare sunt imuabile, valorile nu pot fi şterse doar prin eliminarea unei perechi (cheie, valoare) din cadrul acestora. De aceea, va fi utilizat un indicator de ştergere “piatră funerară” (eng. tombstone marker) pentru a indica faptul că informaţia respectivă nu mai există. În timpul procesului de obţinere a datelor, aceste marcaje maschează valorile reţinute, ascunzându-le de clienţii care interoghează baza de date.

Procesul de citire a datelor implică concatenarea informaţiilor din memorie (a datelor care nu au fost încă scrise pe disc) şi a fişierelor de stocare rezidente pe disc. În cadrul acestui proces, jurnalul de scriere anticipată nu este folosit deloc, el fiind interogat doar în situaţia în care un server s-a oprit din funcţionare înainte ca datele aflate în memorie să fie transferate pe disc.

Întrucât transferul datelor din zonele de memorie tampon pe disc face ca tot mai multe fişiere HFile să fie scrise, HBase implementează un sistem de întreţinere prin care fişierele HFile sunt concatenate în fişiere mai mari folosind un mecanism de compactare. Compactarea este minoră sau majoră. Compactarea minoră reduce numărul de fişiere de stocare prin rescrierea unor fişiere de dimensiuni mai mici în mai puţine fişiere de dimensiuni mai mari. De vreme ce datele sunt sortate în fiecare fişier HFile, procesul de concatenare este rapid, nefiind limitat decât de performanţele de intrare/ieşire ale discului. Compactarea majoră rescrie toate fişierele dintr-o familie de coloane din cadrul unei regiuni într-un singur fişier. Altă caracteristică distinctivă constă în faptul că procesul implică scanarea tuturor perechilor (cheie, valoare), astfel că intrările care sunt marcate ca fiind şterse pot fi ignorate. Tot acum este gestionată şi ştergerea predicatelor, eliminându-se valorile ce au expirat sau cele pentru care există prea multe versiuni.

O astfel de arhitectură este preluată din cadrul arborilor LSM (arbori de concatenare structuraţi în jurnale – eng. log-structured merge trees). Diferenţa constă în faptul că aceştia stochează datele în blocuri formate din mai multe pagini care sunt aranjate pe disc într-o structură asemănătoare arborilor B. Actualizarea (concatenarea) se realizează printr-un mecanism de rotire, în timp ce în cazul HBase acest proces este mai granular în sensul că zona tampon de memorie este salvată sub forma unui fişier de stocare, nefiind concatenată imediat. Compactările realizate în fundal pot fi comparate cu concatenările din cadrul arborilor LSM, însă acestea se realizează la nivelul unui fişier stocat pe disc, fără a fi însă vorba despre actualizări parţiale asupra unor arbori.

HBase are trei componente principale:

  1. biblioteca clientului;
  2. un server de tip master;
  3. mai multe servere de regiune.

Dacă serverele de regiune pot fi adăugate sau şterse în timpul funcţionării sistemului de gestiune pentru baze de date distribuite în funcţie de încărcarea acestuia, serverul de tip master este responsabil pentru repartizarea regiunilor către serverele aferente, folosind în acest sens un produs denumit Apache ZooKeeper, un serviciu de coordonare sigur, persistent, care oferă tuturor utilizatorilor un nivel înalt de disponibilitate.

ZooKeeper este un proiect open-source de sine stătător, parte a Apache Software Foundation. El oferă acces asemănător sistemelor de fişiere, cu fişiere şi directoare (denumite znodes) pe care sistemele distribuite le pot folosi pentru a negocia proprietatea, pentru a înregistra servicii sau pentru a monitoriza actualizările. Fiecare server de regiune îşi creează un nod temporar în cadrul ZooKeeper pe care serverul de tip master îl foloseşte spre a descoperi serverele disponibile sau pentru a identifica erorile la nivelul serverelor sau partiţiilor de reţea. Un nod temporar este legat de sesiunea dintre ZooKeeper şi clientul care l-a creat, folosindu-se un mecanism bazat pe mesaje periodice pentru a detecta momentul în care s-a produs o eroare spre a fi şters, cu relocarea serverelor de regiune şi a datelor corespunzătoare pe alte maşini. ZooKeeper asigură faptul că există o singură instanţă a unui server de tip master care funcţionează la un moment dat de timp, pentru a stoca locaţiile utilizate în procesul de descoperire a regiunilor, ca registru pentru serverele de regiune ca şi pentru alte scopuri. ZooKeeper este o componentă critică fără de care HBase nu este funcţional. Avantajele pe care le aduce ZooKeper sunt datorate proiectării sale distribuite, folosind mai multe servere şi protocolul Zab pentru a-i menţine starea consistentă.

Totodată, serverul de tip master este responsabil pentru gestiunea încărcării serverelor de regiune, distribuind regiunile către noduri mai puţin ocupate, realizându-se astfel echilibrarea acestora. El nu se ocupă cu stocarea datelor şi nu este implicat în procesul de obţinere a informaţiilor din baza de date. Rolul său este doar de a realiza încărcarea uniformă, gestionând starea clusterului, fără a oferi însă servicii de date nici serverelor de regiune şi nici clienţilor, astfel încât gradul său de ocupare este destul de redus. Serverul de tip master gestionează şi modificările la nivelul schemei de date precum şi alte operaţii legate de metadate (cum ar fi crearea de tabele sau de familii de coloane). Responsabilitatea serverelor de regiune constă în tratarea cererilor de citire şi de scriere pentru toate regiunile pe care le gestionează şi totodată pentru împărţirea regiunilor care depăşesc pragul configurat pentru dimensiunea maximă a acestora. Clienţii comunică direct cu serverele de regiune atunci când doresc să realizeze orice fel de operaţii care implică date.

Intern, HBase foloseşte tabele speciale denumite -ROOT- şi .META., în cadrul cărora menţine lista curentă, starea şi locaţia tuturor regiunilor din cluster. Tabela -ROOT- reţine lista tabelelor de regiune .META.. Tabela .META. conţine lista tuturor regiunilor din spaţiul utilizatorilor. Intrările din această tabelă sunt ordonate după denumirea regiunii, aceasta fiind formată din numele tabelei corespunzătoare regiunii din care face parte, rândul de început al regiunii, momentul de timp la care a fost creată şi un rezumat MD5 al acestor informaţii. Întrucât cheile de rând sunt sortate, identificarea unei regiuni care găzduieşte o anumită înregistrare este o problemă de determinarea unei intrări a cărei cheie este mai mare sau egală cu cea a cheii solicitate. Aceste tabele sunt actualizate pe măsură ce sunt realizate tranziţii în cadrul regiunilor, astfel încât starea tuturor regiunilor din cluster să reflecte starea lor curentă. Astfel de operaţii sunt împărţirea unei regiuni, activarea sau dezactivarea acesteia, ştergerea, relansarea unei regiuni de către procesul de echilibrare a încărcării sau în cazul opririi serverului de regiune din cauza unei erori.

Noii clienţi care se conectează la clusterul ZooKeeper obţin locaţia tabelei -ROOT- consultând-o pentru a determina locaţia regiunii .META. care conţine rândul solicitat. Ulterior, va fi realizată o căutare în această tabelă pentru a obţine spaţiul de utilizator al regiunii care găzduieşte informaţiile necesare precum şi locaţia acestuia. Numai după aceasta va interacţiona direct cu serverul de regiune identificat. Pentru a evita realizarea tuturor acestor operaţii de fiecare dată când trebuie să utilizeze informaţii din baza de date, locaţiile obţinute din interogarea tabelelor -ROOT- / .META. vor fi reţinute în zone de memorie tampon (eng. cache). De asemenea, pentru fiecare spaţiu de utilizator al regiunii, vor fi reţinute intervalele pentru cheia de rând (început şi sfârşit), astfel încât să poată determina serverele de regiune care găzduiesc informaţiile solicitate fără a fi necesar să interogheze tabela .META.. Acestea vor continua să fie folosite până în momentul în care se produce o eroare, situaţie în care tabela .META. este consultată din nou pentru a se obţine adresa serverului de regiune. Dacă şi regiunea .META. nu mai este actuală, se recurge la consultarea tabelei -ROOT-.

Ca şi Bigtable, HBase nu oferă un model de date relaţional complet, punând la dispoziţia utilizatorilor un model de date simplu, ce implementează controlul dinamic asupra dispunerii datelor şi asupra formatului acestora. Astfel, API-ul conţine operaţii pentru a crea şi a şterge tabele şi familii de coloane. Totodată, are funcţii pentru a modifica metadatele referitoare la tabele, respectiv familii de coloane, cum ar fi compresia sau dimensiunile blocurilor. Mai mult, există operaţii uzuale pentru clienţi pentru a crea sau a şterge valori precum şi pentru a le obţine, dându-se cheia de rând.

Un API pentru scanare permite iterarea eficientă pentru anumite limite ale rândurilor, specificând şi care coloane vor fi întoarse, respectiv numărul de versiuni pentru fiecare celulă. Coloanele pot fi identificate prin intermediul unor filtre, iar versiunile sunt determinate de intervalele de timp specificate (început şi sfârşit). În plus, sunt implementate şi funcţionalităţi mai avansate. Sistemul HBase oferă suport pentru tranzacţii ce includ un singur rând, implementând secvenţe de tip citeşte-modifică-scrie realizate în mod atomic pentru datele identificate printr-o unică cheie de rând. Deşi nu există tranzacţii pentru operaţii ce implică mai multe rânduri sau mai multe tabele, aceste operaţii pot fi realizate de utilizator în mod secvenţial, prin intermediul unui script, obţinându-se aceleaşi performanţe cu siguranţa accesului la date. Valorile celulelor pot fi interpretate drept contoare, actualizate în mod atomic printr-o singură operaţie astfel că, în ciuda naturii distribuite a arhitecturii, utilizatorii pot folosi acest mecanism pentru a implementa contoare globale, secvenţiale, strict consistente.

De asemenea, există posibilitatea de a rula cod oferit de utilizator în cadrul spaţiului de adrese al serverului. Contextul care suportă aceste operaţii la nivelul serverului este numit coprocesor, codul având acces la datele locale aflate pe server, el putând fi utilizat pentru a implementa sarcini pe seturi de date sau pentru a folosi expresii spre a sumariza datele pe baza diverşilor operatori. Această funcționalitate a fost implementată începând cu versiune 0.91.0 a HBase.

Sistemul HBase este de asemenea integrat cu paradigma MapReduce, oferind metode care convertesc tabelele în surse de date şi în locaţii pentru stocarea datelor de ieşire, specifice sarcinilor de acest tip.

Spre diferenţă de sistemele de baze de date tradiţionale (relaţionale), nu există un limbaj specific (cum ar fi SQL) pentru a interoga datele. Accesul nu este realizat declarativ ci mai degrabă imperativ prin intermediul API-ului de la nivelul utilizatorului. Acestea pot fi accesate printr-un shell specific sau prin limbajul de programare Java.

Shell-ul HBase este o interfaţă în linie de comandă către cluster, care poate fi folosită spre a realiza conexiunea către un server local sau la distanţă şi pentru a interacţiona cu acesta. Sunt oferite atât opţiuni corespunzătoare unui utilizator de tip administrator cât şi opţiuni corespunzătoare unui utilizator de tip client. Toate comenzile disponibile prin intermediul acestuia pot fi accesate şi folosind API-ul corespunzător limbajului de programare Java. Shell-ul HBase este bazat pe JRuby, o implementare a Ruby bazată pe maşina virtuală Java. Acesta foloseşte shell-ul interactiv Ruby (IRB – eng. Interactive Ruby Shell), utilizat pentru a rula comenzi Ruby şi pentru a primi răspuns imediat, moştenind suportul pentru istoria comenzilor şi pentru auto-completare.

Pentru a se realiza conexiunea către un server la distanţă, trebuie creat un director conţinând fişierul de configurare hbase-site.xml, acesta având o proprietate hbase.zookeeper.quorum care indică un alt cluster, shell-ul fiind ulterior pornit specificându-se locaţia la care se găseşte fişierul de configurare ce se doreşte folosit (HBASE_CONF_DIR).
Nu este necesară instalarea Ruby întrucât HBase conţine arhivele jar necesare pentru execuţia comenzilor în shell. Se va utiliza doar script-ul pentru a porni shell-ul ce rulează peste maşina virtuală Java, aceasta reprezentând singura cerinţă obligatorie.

Pornirea shell-ului HBase se face prin comanda hbase (din directorul $HBASE_HOME/bin), care primeşte argumentul shell:

student@aipi2015:/usr/local/hbase/bin$ ./hbase shell

Oprirea shell-ului HBase se face prin comenzile exit sau quit.

O listă a tuturor comenzilor disponibile poate fi obţinută prin intermediul comenzii help, aceasta putând fi de asemenea invocată pentru un grup de comenzi sau pentru o comandă specifică, precizate ca parametri între ghilimele:

hbase(main):001:0> help
hbase(main):002:0> help "COMMAND_GROUP"
hbase(main):003:0> help "COMMAND"

unde COMMAND_GROUP reprezintă un grup de comenzi (situaţie în care sunt afişate toate comenzile din grupul respectiv), iar COMMAND reprezintă o anumită comandă.

Shell-ul HBase poate fi apelat cu o serie de parametrii în linia de comandă, care pot fi obţinuţi dacă se specifică parametrii -h sau –help:

student@aipi2015:/usr/local/hbase/bin$ ./hbase shell [-h | --help]
Usage: shell [OPTIONS] [SCRIPTFILE [ARGUMENTS]]
 
 --format=OPTION                Formatter for outputting results.
                                Valid options are: console, html.
                                (Default: console)
 
 -d | --debug                   Set DEBUG log levels.
 -h | --help                    This help.

Opţiunea format specifică modul în care vor fi afişate rezultatele (variantele posibile fiind console – implicit, respectiv html), în timp ce opţiunile -d sau –debug permit ca shell-ul să fie rulat în modul DEBUG, afişându-se toate informaţiile de pe stivă, în caz că se produce o eroare.

În prezent, formatul html nu este încă implementat, singura opţiune disponibilă pentru formatul rezultatelor fiind console. În cazul în care se apelează shell-ul HBase cu această variantă de afişare a formatului, va fi generată o excepţie NoMethodError: Not yet implemented.
În cadrul shell-ului HBase, modul DEBUG poate fi pornit, respectiv oprit prin comanda debug. Modul curent poate fi verificat prin intermediul comenzii debug?. În cazul în care modul DEBUG este oprit, shell-ul HBase este configurat să afişeze doar mesajele de nivel ERROR, fără a oferi nici un fel de detalii cu privire la stiva de erori în cadrul consolei.

Comenzie sunt grupate în 6 categorii diferite, în funcţie de relaţiile lor semnatice. La scrierea lor, trebuie să se ţină cont de următoarele reguli:

  1. toate denumirile (coloane sau tabele) trebuie specificate între apostroafe;
  2. toate valorile trebuie specificate între ghilimele (folosind reprezentarea octală – precedate de \0 sau hexazecimală – precedate de \x), în caz contrar fiind interpretate ca literali; textul aflat între apostroafe este interpretat ca fiind un literal, în timp ce textul aflat între ghilimele este interpolat, transformând valorile octale sau hexazecimale în octeţi;
  3. parametrii unei comenzi vor fi separaţi folosind virgule;
  4. în cazul în care pentru unele comenzi sunt necesare precizarea unor asocieri de tip (cheie, valoare), acestea trebuie realizate folosind hash-uri Ruby:
    { 'key1' ⇒ 'value1', 'key2' ⇒ 'value2', …, 'keyn' ⇒ 'valuen' }
    astfel că perechile (cheie, valoare) sunt specificate între acolade { }, separarea dintre cheie şi valoare făcându-se prin , iar între mai multe elemente prin virgulă. De regulă, acestea sunt folosite pentru constante predefinite cum ar fi VERSIONS, TTL, COMPRESSION, BLOCKCACHE, MAXLENGTH, situaţie în care valorile nu mai trebuie incluse între apostroafe.

Categoriile de comenzi suportate de HBase sunt:

  1. comenzi generale;
  2. comenzi pentru definirea datelor (DDL);
  3. comenzi pentru manipularea datelor (DML);
  4. comenzi pentru apelul diferitelor utilitare;
  5. comenzi pentru replicare;
  6. comenzi legate de securitate.

Comenzi generale

Funcţionalitatea comenzilor generale constă în posibilitatea de a obţine detalii cu privire la starea clusterului, a versiunii HBase utilizate precum şi a utilizatorului curent:

status afişează starea clusterului; poate fi apelat fără parametrii sau poate primi parametrii 'summary' (implicit), 'simple' sau 'detailed'
hbase> status
hbase> status 'summary'
1 servers, 0 dead, 2.0000 average load
hbase> status 'simple'
hbase> status 'detailed'
version afişează versiunea curentă a bazei de date distribuită HBase instalată
hbase> version
0.98.8-hadoop2, r6cfc8d064754251365e070a10a82eb169956d5fe, Fri Nov 14 18:26:29 PST 2014
whoami afişează utilizatorul curent autentificat în cadrul bazei de date distribuite HBase
hbase> whoami
aipi2014 (auth:SIMPLE)
    groups: aipi2014, adm, cdrom, sudo, dip, plugdev, lpadmin, sambashare

Comenzi pentru Definirea Datelor (DDL)

Comenzile pentru definirea datelor (DDL) dau utilizatorilor posibilitatea de a gestiona tabele, în structura cărora nu pot fi însă specificate decât familiile de coloane.

alter modifică structura / configuraţia unui tabel
În funcţie de configurarea HBase, dată prin proprietatea hbase.online.schema.update.enable, tabelul trebuie să fie dezactivat (eng. disabled) pentru a putea fi modificat, sau poate fi blocat pentru astfel de operaţii.

1. adăugare/modificare/ştergere a familiilor de coloane specificându-se denumirea tabelului şi familia de coloane, ce poate fi indicată fie printr-un şir de caractere, fie printr-un dicţionar, folosind atributul NAME; în cazul HBase nu pot fi modificate definiţiile coloanelor din cadrul unei familii de coloane întrucât, spre diferenţă de acestea, nu sunt statice, fiecare înregistrare având structura proprie.
- pentru adăugarea sau modificarea unor familii de coloane se poate folosi comanda:
hbase> alter 't1', {NAME => 'f1', IN_MEMORY => true}, {NAME => 'f2', VERSIONS => 5}

(la tabela t1 sunt adăugate/modificate familiile de coloane f1 – care va fi reţinută în memorie, respectiv f2 pentru care se vor reţine maxim 5 versiuni)
- pentru ştergerea unei familii de coloane se poate utiliza una din comenzile

hbase> alter 't1', NAME => 'f1', METHOD => 'delete'
hbase> alter 't1', 'delete' => 'f1'

2. schimbarea configuraţia unui tabel
- proprietăţi cu domeniu de vizibilitate pentru întregul tabel (precum MAX_FILESIZE, READONLY, MEMSTORE_FLUSHSIZE, DEFERRED_LOG_FLUSH) pot fi adăugate/modiciate (având asociată o anumită valoare) sau pot fi şterse:

hbase> alter 't1', MAX_FILESIZE => '134217728'
hbase> alter 't1', METHOD => 'table_att_unset', NAME => 'MAX_FILESIZE'

- un coprocesor poate fi adăugat sau şters:

hbase> alter 't1', 'coprocessor'=>'hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2'
hbase> alter 't1', METHOD => 'table_att_unset', NAME => 'coprocessor$1'

Întrucât pot fi configurate mai multe coprocesoare pentru o tabelă, un număr de secvenţă va fi sufixat automat la denumirea atributului, spre a putea fi identificat. Un astfel de atribut are formatul [coprocessor jar file location] | class name | [priority] | [arguments], pentru ca sistemul să ştie cum să încarce clasele respective.

Configuraţiile pot fi specificate prin urmare pentru întregul tabel sau numai pentru o anumită familie de coloane:

hbase> alter 't1', CONFIGURATION => {'hbase.hregion.scan.loadColumnFamiliesOnDemand' => 'true'}
hbase> alter 't1', {NAME => 'f2', CONFIGURATION => {'hbase.hstore.blockingStoreFiles' => '10'}}

HBase permite ca în cadrul unei comenzi să fie specificate mai multe proprietăţi eterogene, fie pentru întregul tabel, fie pentru o familie de coloane:

hbase> alter 't1', { NAME => 'f1', VERSIONS => 3 }, 
    { MAX_FILESIZE => '134217728' }, { METHOD => 'delete', NAME => 'f2' },
    OWNER => 'johndoe', METADATA => { 'mykey' => 'myvalue' }
alter_async modifică structura / configuraţia unui tabel, fără a mai aştepta ca toate regiunile să primească actualizările cu privire la schemă; primeşte ca parametru numele tabelei şi un dicţionar indicând schema familiei de coloane
hbase> alter_async 't1', {NAME => 'f1', IN_MEMORY => true}, {NAME => 'f2', VERSIONS => 5}
hbase> alter_async 't1', NAME => 'f1', METHOD => 'delete'
hbase> alter_async 't1', 'delete' => 'f1'
hbase> alter_async 't1', MAX_FILESIZE => '134217728'
hbase> alter_async 't1', METHOD => 'table_att_unset', NAME => 'MAX_FILESIZE'
hbase> alter_async 't1', 'coprocessor'=>'hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2'
hbase> alter_async 't1', METHOD => 'table_att_unset', NAME => 'coprocessor$1'
alter_status verifică statutul comenzii alter sau alter_async; primeşte ca parametru denumirea tabelei, întorcând ca rezultat numărul de regiuni din tabelă care au primit schema actualizată
hbase> alter_status 't1'
create creează un tabel; trebuie precizate numele tabelului şi un set de specificaţii (minim unul) pentru familia de coloane (acestea pot fi un şir de caractere indicând denumirea sau un dicţionar indicând în mod obligatoriul atributul NAME);
hbase> create 't1', 'f1', 'f2'
hbase> create 't1', {NAME => 'f1'}, {NAME => 'f2'}
hbase> create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}
hbase> create 't1', {NAME => 'f1', CONFIGURATION => {'hbase.hstore.blockingStoreFiles' => '10'}}

opţional, pot fi precizate şi elemente de configuraţie a tabelei, recomandându-se ca astfel de opţiuni să fie indicate la sfârşit

hbase> create 't1', 'f1', SPLITS => ['10', '20', '30', '40']
hbase> create 't1', 'f1', SPLITS_FILE => 'splits.txt', OWNER => 'johndoe'

tabela poate fi preîmpărţită într-un număr de regiuni folosind opţiunea SPLITALGO care poate avea valorile “HexStringSplit”, “UniformSplit” sau numele unei clase

hbase> create 't1', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
hbase> create 't1', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit', 
              CONFIGURATION => {'hbase.hregion.scan.loadColumnFamiliesOnDemand' => 'true'}}

de asemenea, se poate specifica o referinţă la tabela creată, care se poate utiliza ulterior pentru apelul de metode specifice

hbase> t1 = create 't1', 'f1'
describe descrie structura tabelei indicată prin denumirea ei
hbase> describe 't1'
disable dezactivează o tabelă indicată prin denumirea ei
hbase> disable 't1'
disable_all dezactivează toate tabelele care respectă un anumit format, indicat sub formă de expresie regulată
hbase> disable_all 't.*'
drop şterge o tabelă indicată prin denumirea sa
hbase> drop 't1'

Pentru a putea fi ştearsă o tabelă trebuie să fie mai întâi dezactivată.

drop_all şterge toate tabelele care respectă un anumit format, indicat sub formă de expresie regulată
hbase> drop_all 't.*'
enable activează o tabelă indicată prin denumirea ei
hbase> enable 't1'
enable_all activează toate tabelele care respectă un anumit format, indicat sub formă de expresie regulată
hbase> enable_all 't.*'
exists verifică dacă o tabelă indicată prin denumirea sa există
hbase> exists 't1'
is_disabled verifică dacă o tabelă indicată prin denumirea sa este dezactivată
hbase> is_disabled 't1'
is_enabled verifică dacă o tabelă indicată prin denumirea sa este activată
hbase> is_enabled 't1'
list afişează denumirile tuturor tabelelor existente în baza de date
hbase> list

opţional, poate fi indicată o expresie regulată care filtrează conţinutul tabelelor afişate în funcţie de respectarea şablonului respectiv

hbase> list 't.*'
show_filters afişează toate filtrele care au fost definite pentru baza de date
hbase> show_filters

Filtrele care pot fi definite în cazul unei baze de date distribuite HBase sunt: ColumnPrefixFilter, TimestampsFilter, PageFilter, MultipleColumnPrefixFilter, FamilyFilter, ColumnPaginationFilter, SingleColumnValueFilter, RowFilter, QualifierFilter, ColumnRangeFilter, ValueFilter, PrefixFilter, SingleColumnValueExcludeFilter, ColumnCountGetFilter, InclusiveStopFilter, DependentColumnFilter, FirstKeyOnlyFilter, KeyOnlyFilter.

Comenzi pentru Manipularea Datelor (DML)

Comenzile pentru manipularea datelor (DML) implementează funcţionalităţile legate de transferul datelor de la utilizator spre baza de date, respectiv dinspre baza de date la utilizator.

count indică numărul de înregistrări dintr-o tabelă; implicit, este afişat rezultatul obţinut după parcurgerea a 1000 de rânduri, însă acest interval poate fi specificat ca parametru; de asemenea, implicit sunt introduse în zona tampon de memorie (eng. cache) câte 10 înregistrări, însă şi acest parametru poate fi configurat (o astfel de valoare poate fi mai mare doar în situaţia în care dimensiunea înregistrărilor este mică, astfel încât să nu se depăşească memoria alocată).
hbase> count 't1'
hbase> count 't1', INTERVAL => 100000
hbase> count 't1', CACHE => 1000
hbase> count 't1', INTERVAL => 10, CACHE => 1000

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.count
hbase> t.count INTERVAL => 100000
hbase> t.count CACHE => 1000
hbase> t.count INTERVAL => 10, CACHE => 1000

O astfel de operaţie poate dura foarte mult timp, având în vedere dimensiunea mare de date care poate fi gestionată de o tabelă HBase, recomandându-se ca o astfel de informaţie să fie obţinută prin rularea unei aplicaţii de tip MapReduce, ce poate fi executată astfel:

student@aipi2015:/usr/local/hadoop/bin/hadoop$ jar hbase.jar rowcount
delete marchează o valoare a unei celule (specificată prin coordonatele tabel/cheie de rând/coloană şi opţional amprentă de timp) ca fiins ştearsă
hbase> delete 't1', 'r1', 'c1', ts1

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.delete 'r1', 'c1', ts1

La scanare, o celulă care este marcată ca fiind ştearsă va suprima versiunile mai vechi.

deleteall şterge celulele din cadrul unui rând al unui tabel specificat printr-o cheie de rând; opţional, pot fi indicate o coloană şi o amprentă de timp
hbase> deleteall 't1', 'r1'
hbase> deleteall 't1', 'r1', 'c1'
hbase> deleteall 't1', 'r1', 'c1', ts1

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.deleteall 'r1'
hbase> t.deleteall 'r1', 'c1'
hbase> t.deleteall 'r1', 'c1', ts1
get afişează conţinutul unui rând sau al unei celule; trebuie indicate denumirea tabelului şi opţional un dicţionar de coloane, o amprentă de timp, un interval sau versiuni
hbase> get 't1', 'r1'
hbase> get 't1', 'r1', {TIMERANGE => [ts1, ts2]}
hbase> get 't1', 'r1', {COLUMN => 'c1'}
hbase> get 't1', 'r1', 'c1'
hbase> get 't1', 'r1', {COLUMN => ['c1', 'c2']}
hbase> get 't1', 'r1', 'c1', 'c2'
hbase> get 't1', 'r1', ['c1', 'c2']
hbase> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => ts1}
hbase> get 't1', 'r1', {COLUMN => 'c1', TIMERANGE => [ts1, ts2], VERSIONS => 4}
hbase> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => ts1, VERSIONS => 4}
hbase> get 't1', 'r1', {FILTER => "ValueFilter(=, 'binary:abc')"}

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.get 'r1'
hbase> t.get 'r1', {TIMERANGE => [ts1, ts2]}
hbase> t.get 'r1', {COLUMN => 'c1'}
hbase> t.get 'r1', {COLUMN => ['c1', 'c2', 'c3']}
hbase> t.get 'r1', {COLUMN => 'c1', TIMESTAMP => ts1}
hbase> t.get 'r1', {COLUMN => 'c1', TIMERANGE => [ts1, ts2], VERSIONS => 4}
hbase> t.get 'r1', {COLUMN => 'c1', TIMESTAMP => ts1, VERSIONS => 4}
hbase> t.get 'r1', {FILTER => "ValueFilter(=, 'binary:abc')"}
hbase> t.get 'r1', 'c1'
hbase> t.get 'r1', 'c1', 'c2'
hbase> t.get 'r1', ['c1', 'c2']

În afară de formatul toStringBinary, comanda get suportă şi formatare particularizată pentru fiecare coloană. Un utilizator poate adăuga un obiect de formatare (FORMATTER) prin indicarea sa în cadrul comenzii get. Acesta poate fi o metodă a clasei org.apache.hadoop.hbase.util.Bytes, sau o clasă definită de utilizator pentru care se indică şi metoda utilizată c(MyFormatterClass).format.

hbase> get 't1', 'r1' {COLUMN => ['cf:qualifier1:toInt',   
    'cf:qualifier2:c(org.apache.hadoop.hbase.util.Bytes).toInt'] }

Un obiect de formatare nu poate fi specificat decât pentru o singură coloană, nu pentru toate coloanele din cadrul unei familii de coloane.

get_counter întoarce un contor pentru valorile unei celule specificată prin coordonate precum tabelul, cheia de rând şi coloana; o celulă ar trebui să fie gestionată printr-o funcţie de incrementare atomică, iar datele ar trebui să fie codificate binar
hbase> get_counter 't1', 'r1', 'c1'

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.get_counter 'r1', 'c1'
incr incrementează valoarea unei celule identificată prin coordonate precum tabelul, cheia de rând şi coloana; implicit, incrementarea se face cu valoarea 1, însă alternativ pot fi specificate şi alte valori
hbase> incr 't1', 'r1', 'c1'
hbase> incr 't1', 'r1', 'c1', 1
hbase> incr 't1', 'r1', 'c1', 10

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.incr 'r1', 'c1'
hbase> t.incr 'r1', 'c1', 1
hbase> t.incr 'r1', 'c1', 10
put specifică valoarea unei celule identificată prin coordonate precum tabelul, cheia de rând, coloana şi opţional amprenta de timp
hbase> put 't1', 'r1', 'c1', 'value', ts1

comanda pot fi rulată şi pe o referinţă la un tabel

hbase> t.put 'r1', 'c1', 'value', ts1
scan scanează o tabelă, primind ca parametrii denumirea acesteia şi opţional un dicţionar conţinând diferite specificaţii (TIMERANGE, FILTER, LIMIT, STARTROW, STOPROW, TIMESTAMP, MAX_LENGTH, COLUMNS, CACHE); în cazul în care nu sunt specificate coloane, toate coloanele tabelei vor fi scanate; dacă se doreşte scanarea tuturor coloanelor dintr-o familie de coloane, identificatorul acestuia va fi lăsat vid ('familyname:'); filtrul poate fi specificat fie folosind şirul de caractere care îl identifică, fie incluzând numele pachetului din care face parte
hbase> scan 'hbase:meta'
hbase> scan 'hbase:meta', {COLUMNS => 'info:regioninfo'}
hbase> scan 't1', {COLUMNS => ['c1', 'c2'], LIMIT => 10, STARTROW => 'xyz'}
hbase> scan 't1', {COLUMNS => 'c1', TIMERANGE => [1303668804, 1303668904]}
hbase> scan 't1', {FILTER => "(PrefixFilter ('row2') AND
    (QualifierFilter (>=, 'binary:xyz'))) AND (TimestampsFilter ( 123, 456))"}
hbase> scan 't1', {FILTER =>
    org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1, 0)}

există şi opţiunile CACHE_BLOCKS ce permite specificarea transferului datelor în zona de memorie tampon, respectiv RAW care transmite scanerului să întoarcă toate celulele

  
hbase> scan 't1', {COLUMNS => ['c1', 'c2'], CACHE_BLOCKS => false}
hbase> scan 't1', {RAW => true, VERSIONS => 10}

Implicit, datele sunt transferate în zona de memorie tampon.
Prin parametrul RAW vor fi incluse inclusiv celulele care sunt marcate pentru ştergere şi celulele care nu au fost încă şterse. O astfel de opţiune nu poate fi însă folosită pentru a se afişa doar anumite coloane. Implicit, această opţiune este dezactivată.

Ca şi în cazul comenzii get, există posibilitatea formatării unei anumite coloane, folosind metode din pachetul org.apache.hadoop.hbase.util.Bytes sau dintr-o clasă definită de utilizator, comanda putând fi rulată şi pe o referinţă la un tabel (cu toate proprietăţile pe care le implementează), după ce aceasta este obţinută.

hbase> t = get_table 't'
hbase> t.scan
truncate dezactivează, şterge şi apoi recreează tabela specificată prin denumirea sa
hbase> truncate 't1'

Comenzi pentru Apelul unor Utilitare

În cazul comenzilor pentru apelul diferitelor utilitare, sunt implementate de regulă operaţii administrative.

assign asociază o regiune la un server
hbase> assign 'REGIONNAME'
hbase> assign 'ENCODED_REGIONNAME'

O astfel de comandă trebuie să fie utilizată cu precauţie, datorită faptului că regiunea poate fi deja asociată la un anumit server, ceea ce va forţa să se realizeze asocierea specificată în comandă.

balance_switch activează/dezactivează procesul de echilibrare a serverelor în funcţie de parametrul cu care este rulat; comanda întoarce starea anterioară a procesului de echilibrare a serverelor de regiune
hbase> balance_switch true
hbase> balance_switch false
balancer declanşează procesul de echilibrare a serverelor de regiune din cadrul clusterului; comanda întoarce true în cazul în care procesul de echilibrare a serverelor de regiune a rulat, transmiţând serverelor de regiune să îşi deasocieze toate regiunile în scopul realizării unui echilibru al încărcării (în continuare desfăşurându-se în mod asincron un proces de reasociere); comanda întoarce false dacă procesul de echilibrare a serverelor de regiune nu a rulat datorită faptului că regiunile se află în tranziţie
hbase> balancer
close_region închide o regiune (specificată prin denumirea sa – REGIONAME), solicitând serverului master să realizeze această operaţie, sau în cazul în care este specificat un nume de server de regiune (SERVER_NAME), acesta va fi desemnat pentru îndeplinirea comenzii; în timp ce serverul master are nevoie de întreaga adresă a regiunii, serverul de regiune poate realiza această operaţie transmiţându-i-se doar numele codificat al acesteia; indiferent de soluţia adoptată, comanda va fi rulată de serverul de regiune care găzduieşte regiunea în cauză, fără implicarea serverului master, care nu este conştient de realizarea acestei operaţii; o regiune rămâne închisă până la apelul comenzii assign; pentru a asocia regiunea altui server de pe cluster, vor fi folosite comenzile move sau unassign.
hbase> close_region 'REGIONNAME'
hbase> close_region 'REGIONNAME', 'SERVER_NAME'
hbase> close_region 'ENCODED_REGIONNAME'
hbase> close_region 'ENCODED_REGIONNAME', 'SERVER_NAME'

REGIONNAME are forma TestTable,0094429456,1289497600452.527db22f95c8a9e0116f0cc13c680396, unde 1289497600452 reprezintă codul de start al serverului de regiune (SERVER_NAME este format din adresă, port şi codul de start, cum ar fi host187.example.com,60020,1289493121758) – numele serverului de regiune putând fi obţinut din comanda status 'detailed' sau folosind interfaţa web, iar 527db22f95c8a9e0116f0cc13c680396 reprezintă numele codificat al regiunii.

compact compactează toate regiunile din tabelul transmis ca parametru, putând primi şi un rând al unei regiuni spre a compacta doar respectiva regiune; de asemenea, poate fi compactată o singură familie de coloane în cadrul unei regiuni sau o familie de coloane în cadrul unui tabel
hbase> compact 't1'
hbase> compact 'r1'
hbase> compact 'r1', 'c1'
hbase> compact 't1', 'c1'
flush transmite pe disc în fişiere HFile toate regiunile unui tabel, sau regiunea corespunzătoare unui anumit rând
hbase> flush 'TABLENAME'
hbase> flush 'REGIONNAME'
hbase> flush 'ENCODED_REGIONNAME'
hlog_roll salvează starea jurnalului de scrieri prin transmiterea sa către un alt fişier; metoda ar trebui să primească drept parametru numele serverului de regiune
hbase> hlog_roll
major_compact realizează o compactare majoră pentru tabelul transmis ca parametru, sau în cazul în care se doreşte ca o singură regiune să sufere acest proces, se indică un rând al regiunii respective; totodată, poate fi compactată o familie de coloane în cadrul unei regiuni, respectiv în cadrul unei tabele, prin specificarea ecestor valori
hbase> major_compact 't1'
hbase> major_compact 'r1'
hbase> major_compact 'r1', 'c1'
hbase> major_compact 't1', 'c1'
move mută o regiune; în cazul în care nu se specifică un server de regiune căruia îi va fi asociată, transferul se face către un server de regiune ales arbitrar
hbase> move 'ENCODED_REGIONNAME'
hbase> move 'ENCODED_REGIONNAME', 'SERVER_NAME'

În cazul acestei comenzi, trebuie transmis numele codificat al regiunii.

split va împărţi întreaga tabelă sau poate fi transmisă doar o regiune pentru ca operaţia să se refere doar la aceasta; poate fi specificat şi un parametru care să indice o anumită cheie pentru regiunea în cauză
hbase> split 'tableName'
hbase> split 'regionName'
hbase> split 'tableName', 'splitKey'
hbase> split 'regionName', 'splitKey'

Ca denumire a regiunii se va specifica numele tabelei, cheia de start şi identificatorul.

unassign deasociază o regiune, ceea ce presupune că aceasta va fi închisă în locaţia curentă şi deschisă la noua locaţie; dacă se doreşte forţarea realizării acestei operaţii se va rula cu parametrul true, ştergându-se stările reţinute în memorie de serverul de tip master înainte de realizarea realocării
hbase> unassign 'REGIONNAME'
hbase> unassign 'REGIONNAME', true
hbase> unassign 'ENCODED_REGIONNAME'
hbase> unassign 'ENCODED_REGIONNAME', true

Dacă în urma acestei operaţii se va produce o anomalie de tipul asocierii duble a regiunii către mai multe servere, trebuie rulată comanda hbck -fix.

zk_dump afişează starea clusterului HBase, pe baza informaţiilor deţinute de ZooKeeper
hbase> zk_dump

Comenzi pentru Replicarea Datelor

HBase oferă utilizatorilor şi posibilitatea de a gestiona modul în care sunt replicate datele în cadrul clusterelor, prin comenzile pentru replicare.

add_peer adaugă un cluster pe care să se realizeze replicarea, primind un identificator (de tip short) şi cheia cluster-ului care reprezintă calea completă pentru ca HBase să se poată conecta la acesta având forma hbase.zookeeper.quorum:hbase.zookeeper.property.clientPort:zookeeper
hbase> add_peer '1', "server1.cie.com:2181:/hbase"
hbase> add_peer '2', "zk1,zk2,zk3:2182:/hbase-prod"
disable_peer opreşte fluxul de replicare către cluster-ul specificat prin intermediul unui identificator, reţinându-se în continuare valorile care trebuie replicate
hbase> disable_peer '1'
enable_peer porneşte replicarea către cluster cluster-ul specificat prin intermediul unui identificator, continuându-se cu valorile ce trebuiau replicate atunci când opţiunea a fost dezactivată
hbase> enable_peer '1'
list_peers afişează lista tuturor clustelor pe care se realizează replicarea
hbase> list_peers
remove_peer opreşte fluxul de replicare către custerul specificat prin intermediul unui identificator, ştergând toate meta-informaţiile despre acesta
hbase> remove_peer '1'
start_replication reporneşte toate funcţionalităţile legate de replicare; starea în care se găseşte fiecare flux în momentul în care porneşte nu este determinată
hbase> start_replication
stop_replication opreşte toate funcţionalităţile legate de replicare; starea în care se găseşte fiecare flux în momentul în care se opreşte nu este determinată
hbase> stop_replication
Comenzile start_replication şi stop_replication trebuie utilizate doar în situaţii critice legate de încărcare.

Comenzi pentru Implementarea unor Politici de Securitate

În cadrul HBase sunt definite comenzi legate de securitate, ce stabilesc permisiunile asupra unor obiecte ale tabelelor.

grant acordă utilizatorilor drepturi specifice
grant <user> <permissions> [<table> [<column family> [<column qualifier>]]

- user este numele utilizatorului autentificat în baza de date
- permissions poate fi 0 sau mai multe litere din setul RWXCA, având semnificaţia R(ead), W(rite), (E)X(ecute), C(reate), A(dmin)
- table, columnfamily și columnidentifier reprezintă denumirile tabelei, familiei de coloane şi coloanei pentru care sunt acordate drepturile respective

hbase> grant 'bobsmith', 'RWXCA'
hbase> grant 'bobsmith', 'RW', 't1', 'f1', 'col1'
revoke revocă anumite drepturi de acces ale unui utilizator
revoke <user> [<table> [<column family> [<column qualifier>]]
hbase> revoke 'bobsmith'
hbase> revoke 'bobsmith', 't1', 'f1', 'col1'

Nu există posibilitatea de a revoca doar o parte dintre drepturile acordate utilizatorului, acestea trebuie şterse în totalitate, pentru ca ulterior să se specifice drepturile de acces la care acesta urmează să fie limitat.

user_permission afişează drepturile de acces ale unui utilizator; poate primi ca parametru denumirea unei tabele pentru a se determina drepturile de acces asupra obiectelor acesteia
user_permission <table>
hbase> user_permission
hbase> user_permission 'table1'

În cazul în care se doreşte rularea unui script, acesta poate fi transmis ca parametru comenzii hbase shell, după execuţia acestuia, terminalul revenind la starea sa iniţială:

student@aipi2015:/usr/local/hbase/bin$ ./hbase shell script.rb

O alternativă este reprezentată de a executa un script folosind interpretorul JRuby, ceea ce presupune că acesta va fi rulat ca o aplicaţie Java.

student@aipi2015:/usr/local/hbase/bin$ ./hbase org.jruby.Main script.rb

Shell-ul HBase permite utilizarea în cadrul său a unor metode Java şi totodată utilizarea unor instrucţiuni repetitive pentru popularea tabelelor cu valori de test.

Există numeroase alte posibilităţi de a accesa informaţiile conţinute într-o bază de date distribuită HBase, acest fapt putând fi realizat prin aplicaţii scrise în aproape orice limbaj de programare, în care apelurile de metode încapsulează invocări ale comenzilor definite de API-ul specific, dezvoltat folosind limbajul de programare Java. Astfel, servicii web de tip REST, Thrift (folosit de Facebook) sau Avro (proiect Apache) sunt doar câteva dintre soluţiile avute la îndemână.

laboratoare/laborator09b.txt · Last modified: 2015/10/02 11:55 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0