Scott Tiger Tech Blog

Blog technologiczny firmy Scott Tiger S.A.

Apache HBase

Autor: Piotr Karpiuk o poniedziałek 9. Marzec 2015

HBase to otwartoźródłowa, zaimplementowana w Javie, rozproszona baza danych inspirowana Googlowym BigTable. Jest częścią projektu Apache Hadoop i przechowuje dane w HDFS (Hadoop Distributed FileSystem). Jest to przykład tzw. kolumnowej NoSQLowej bazy danych, pozwalającej na przechowywanie w sposób odporny na awarie dużej ilości danych rzadkich (ang. sparse data) – które w relacyjnej bazie wymagałyby tabel z dużą ilością przeważnie pustych kolumn.

Pierwotnie HBase był tworzony z myślą o przetwarzaniu języka naturalnego, a od czasu przejęcia projektu przez Apache z bazy korzysta obecnie szereg firm (w tym Twitter, Stumbleupon, eBay, Yahoo!), a bodaj najbardziej spektakularne jest użycie tej bazy przez Facebooka do implementacji komunikatora internetowego Facebook Messenger.

Powszechna wiedza głosi, że sens użycia HBase pojawia się dopiero przy przetwarzaniu co najmniej 100 GB danych przy użyciu min. 5 maszyn w klastrze.

Autorzy dokumentacji używają pojęć nawiązujących do modelu relacyjnego: tabela, wiersz, kolumna – ale jest to bardzo kontrowersyjny pomysł. Osobie przyzwyczajonej do świata relacyjnych baz danych w miarę wgryzania się w HBase oczy będą się coraz bardziej otwierać ze zdumienia. W rzeczy samej, HBase wobec Oracla jest jak zły brat bliźniak, Bizarro, mr. Hyde czy Frankenstein.

Spójrzmy na poniższy rysunek, objaśniający model danych omawianej dzisiaj bazy:

W tabeli mamy dowolnie wiele wierszy, każdy identyfikowany unikalnym kluczem. Kolumny są pogrupowane w rodziny kolumn (zwane też superkolumnami). O ile rodzin kolumn zwykle jest kilka, o tyle samych kolumn mogą być miliony. HBase nie jest transakcyjna i zapewnia atomowość na poziomie rekordu (wiersza), przy czym mamy wersjonowanie: pamiętane są domyślnie 3 ostatnie wersje każdego rekordu opatrzone stemplami czasowymi. Sens istnienia superkolumn jest taki, że dla każdej z nich można zdefiniować inne parametry bazy danych, np. rodzaj kompresji danych (GZ, LZO), poziom redundancji, czas po jakim dane mają być usuwane, czy wersjonowanie. Modyfikacja parametrów superkolumny jest kosztowna – pociąga za sobą utworzenie nowej superkolumny z nową specyfikacją i skopiowanie wszystkich danych – dlatego warto ustawić parametry na docelowe zanim zacznie się wstawiać dane. Wartości kolumn nie mają typów i są traktowane jako ciągi bajtów.

W zasadzie, być może zamiast kurczowo trzymać się nomenklatury nazewniczej z relacyjnych baz danych lepiej byłoby spojrzeć na model danych HBase jak na 4-poziomową mapę asocjacyjną (kolejne poziomy to tabela, klucz, superkolumna i kolumna).

Nazwę kolumny określa się mianem kwalifikatora kolumny (ang. column qualifier). Połączenie klucza wiersza i pełnej nazwy kolumny (wraz z nazwą rodziny) zapisuje się w postaci table/family:qualifier.

Rekordy w bazie są posortowane wedle klucza i podzielone na rozłączne regiony, przy czym za każdy region odpowiedzialna jest inna maszyna klastra.

HBase nie posiada języka zapytań, nie ma indeksów. Zapewnione jest tylko skanowanie całej tabeli i bardzo szybki dostęp do rekordu po kluczu i do wartości kolumny w rekordzie, jak również Hadoopowy mechanizm MapReduce.

Facebook używa HBase jako głównego komponentu swojej infrastruktury komunikatów, zarówno do przechowywania komunikatów jak i odwróconego indeksu (ang. inverted index) na potrzeby wyszukiwania.
W tabeli implementującej indeks:

  • Kluczem wiersza jest ID użytkownika.
  • Kwalifikatorami kolumn są słowa występujące w komunikatach tego użytkownika.
  • Stemple czasowe są identyfikatorami komunikatów zawierających to słowo.

W ten sposób wykorzystywane jest wersjonowanie.

W przykładach poniżej będziemy używać powłoki napisanej w języku JRuby, ale są też inne sposoby komunikacji z bazą (najpopularniejszy jest Thrift):

Nazwa Metoda połączenia Dojrzałość
Shell Bezpośrednia Tak
Java API Bezpośrednia Tak
Thrift Protokół binarny Tak
REST HTTP Tak
Avro Protokół binarny Nie

Zabawmy się

Na szczęście, aby się pobawić bazą na swoim laptopie, możemy użyć HBase do pracy na jednej maszynie. Domyślnie HBase używa katalogu tymczasowego do zapisu danych, co zwykle oznacza utratę danych po restarcie maszyny.

Po ściągnięciu pliku archiwum bazy HBase rozpakowujemy go. Plik konfiguracyjny znajduje się w {HBASE_HOME}/conf/hbase-site.xml.

Bazę startujemy poleceniem

    $ ${HBASE_HOME}/bin/start-hbase.sh

zamykamy poleceniem stop-hbase.sh, a logi (pod UNIXem) przeglądamy np. za pomocą polecenia:

    $ find ${HBASE_HOME}/logs -name "hbase-*.log" -exec tail -f {} \;

Po uruchomieniu bazy warto przejść do shella aby wydawać polecenia:

    $ ${HBASE_HOME}/bin/hbase shell

W shellu utwórzmy tabelę wiki z jedną superkolumną o nazwie text:

    hbase> create 'wiki', 'text'

Teraz możemy wstawić wiersz do kolumny o pustym kwalifikatorze:

    hbase> put 'wiki', 'Home', 'text:', 'Welcome to the wiki!'

i odczytać go:

    hbase> get 'wiki', 'Home', 'text:'

Informacje na temat tabeli zwraca polecenie describe:

    hbase> describe 'wiki'

Zmodyfikujmy parametry superkolumny text i dodajmy superkolumnę revision, w której będziemy trzymać kolumny author i comment; będziemy przechowywać całą historię zmian, a nie tylko 3 ostatnie wersje. Aby wykonać te operacje, musimy przestawić tabelę wiki w tryb offline:

    hbase> disable 'wiki'
    hbase> alter 'wiki' { NAME => 'text', VERSIONS =>
    hbase*   org.apache.hadoop.hbase.HConstants::ALL_VERSIONS }
    hbase> alter 'wiki' { NAME => 'revision', VERSIONS =>
    hbase*   org.apache.hadoop.hbase.HConstants::ALL_VERSIONS }
    hbase> enable 'wiki'

Możemy teraz wstawiać nowe wiersze np. tak:

    hbase> put_many 'wiki', 'Some title', {
    hbase*  "text:" => "Some article text",
    hbase*  "revision:author" => "jschmoe",
    hbase*  "revision:comment" => "no comment" }

Konsola HBase napisana jest w języku JRuby i wykonuje się na maszynie wirtualnej Javy (JVM). Działa nie tylko w trybie interaktywnym. Można też napisać wsadowy skrypt w JRubym (np. pobierający na STDIN XML z artykułami polskiej Wikipedii pobranymi z pliku http://dumps.wikimedia.org/plwiki/latest/plwiki-latest-pages-articles.xml.bz2 i wstawiający rekordy do naszej tabeli wiki).

    hbase> ${HBASE_HOME}/bin/hbase shell <your_script> [<optional_arguments> ...]

Utwórzmy drugą tabelę, w której będziemy trzymać powiązania między artykułami (w obie strony):

    hbase> create 'links', {
             NAME => 'to', VERSIONS => 1, BLOOMFILTER => 'ROWCOL'
           }, {
             NAME => 'from', VERSIONS => 1, BLOOMFILTER => 'ROWCOL'
           }

Zamysł jest taki, że kluczem wiersza w tej tabeli będzie tytuł artykułu, w superkolumnie from nazwami kolumn będą tytuły artykułów źródłowych, a w superkolumnie to nazwami kolumn będą tytuły artykułów docelowych. Zauważ, że liczba kolumn w poszczególnych wierszach tabeli będzie różna i te kolumny będą miały bardzo zróżnicowane nazwy, w zależności od linków między artykułami w kolejnych artykułach Wikipedii.

Teraz można napisać skrypt, który przeskanuje tabelę wiki, z każdego artykułu wyczesze linki i wstawi je do tabeli links. Gdy to już zrobimy, możemy zapytać o linki artykułu o zadanym tytule:

    hbase> get 'links', 'Star Wars'

a nawet o linki z całego przedziału artykułów o posortowanych tytułach pomiędzy „Akacja” a „Armata”:

    hbase> scan 'links', STARTROW => "Akacja", ENDROW => "Armata"

Jeśli chcemy policzyć wiersze w tabeli, możemy to zrobić tak:

    hbase> count 'wiki', INTERVAL => 100000, CACHE => 10000

Z uwagi na swoją rozproszoną architekturę, HBase nie zna z góry liczby wierszy i musi przeskanować tabelę. Na szczęście maksymalnie zrównolegli to zadanie, więc prawdopodobnie nie poczekamy długo na wynik.

Do chmury

Jak już wspomniano wyżej, w praktyce bazę HBase jest sens uruchamiać w klastrze, np. w chmurze. Warto w tym celu użyć narzędzia Apache Whirr: pozwala ono na łatwe uruchomienie w chmurze (Amazon EC2, RackSpace) klastra maszyn obsługujących technologie takie jak Hadoop, HBase, Cassandra, Voldemort, ZooKeeper, MongoDB, czy ElasticSearch. W naszym przypadku, gdy chcemy uruchomić klaster maszyn HBase na Amazon EC2, wystarczy przygotować krótki plik konfiguracyjny (trzeba wpisać klucz API do usługi Amazon Web Services):

    # service provider
    whirr.provider=aws-ec2
    whirr.identity=your AWS_ACCESS_KEY_ID here
    whirr.credential=your AWS_SECRET_ACCESS_KEY here

    # ssh credentials
    whirr.private-key-file=keys/id_rsa
    whirr.public-key-file=keys/id_rsa.pub

    # cluster configuration
    whirr.cluster-name=myhbasecluster
    whirr.instance-templates=\
      1 zookeeper+hadoop-namenode+hadoop-jobtracker+hbase-master,\
      5 hadoop-datanode+hadoop-tasktracker+hbase-regionserver

    # HBase and Hadoop version configuration
    whirr.hbase.tarball.url=http://apache.cu.be/hbase/hbase-0.90.3/hbase-0.90.3.tar.gz
    whirr.hadoop.tarball.url=http://archive.cloudera.com/cdh/3/hadoop-0.20.2-cdh3u1.tar.gz

Teraz uruchamiamy Whirrla:

    $ whirr launch-cluster --config hbase.properties

Po dłuższej chwili w chmurze zacznie działać klaster 6 maszyn. W pliku ~/.whirr/myhbasecluster/instances mamy ich nazwy domenowe. Możemy zacząć komunikować się z pierwszą maszyną klastra. Aby zlikwidować klaster, wystarczy napisać:

    $ whirr destroy-cluster --config hbase.properties

Share and Enjoy:
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Śledzik
  • Blip
  • Blogger.com
  • Gadu-Gadu Live
  • LinkedIn
  • MySpace
  • Wykop

Zostaw komentarz

XHTML: Możesz użyć następujących tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>