6.1 Kto wynalazł HBase i dlaczego

W tym wykładzie opowiemy o tak wspaniałym narzędziu jak Hbase, które w ostatnim czasie zyskało ogromną popularność: na przykład Facebook używa go jako podstawy swojego systemu przesyłania wiadomości, a to już wiele mówi.

Na wykładzie będzie mowa o koncepcji Big Table i jej darmowej implementacji, cechach działania i różnicach zarówno od klasycznych relacyjnych baz danych (takich jak MySQL i Oracle) jak i magazynów klucz-wartość takich jak Redis, Aerospike czy memcached. Jak zwykle zacznijmy od historii zagadnienia. Podobnie jak wiele innych projektów BigData, Hbase narodził się z koncepcji opracowanej przez Google. Zasady stojące za Hbase zostały opisane w artykule Bigtable: A Distributed Storage System for Structured Data .

Jak omówiliśmy w poprzednich wykładach, zwykłe pliki całkiem dobrze nadają się do wsadowego przetwarzania danych przy użyciu paradygmatu MapReduce. Z drugiej strony informacje przechowywane w plikach są raczej niewygodne w aktualizacji; Pliki pozbawione są również możliwości losowego dostępu. Do szybkiej i wygodnej pracy z losowym dostępem istnieje klasa systemów nosql, takich jak przechowywanie klucz-wartość, takich jak Aerospike, Redis, Couchbase, Memcached. Jednak przetwarzanie wsadowe jest zwykle bardzo niewygodne w tych systemach. Hbase to próba połączenia wygody przetwarzania wsadowego z wygodą aktualizacji i swobodnego dostępu.

6.2 Model danych

HBase to rozproszona, zorientowana na kolumny, wielowersyjna baza danych klucz-wartość.

  • Dane są zorganizowane w tabele indeksowane przez klucz podstawowy o nazwie RowKey w Hbase.
  • Dla każdego klucza RowKey można przechowywać nieograniczony zestaw atrybutów (lub kolumn).
  • Kolumny są zorganizowane w grupy kolumn zwane Rodzina kolumn. Z reguły kolumny o tym samym wzorcu użytkowania i przechowywania są łączone w jedną rodzinę kolumn.
  • Dla każdego atrybutu można przechowywać kilka różnych wersji. Różne wersje mają różne znaczniki czasu.

Rekordy są fizycznie przechowywane w kolejności posortowanej według RowKey. W takim przypadku dane odpowiadające różnym rodzinom kolumn są przechowywane oddzielnie, co pozwala w razie potrzeby odczytać dane tylko z żądanej rodziny kolumn.

Kiedy określony atrybut zostanie usunięty, nie jest on fizycznie usuwany natychmiast, ale jest oznaczony specjalną flagą nagrobka. Fizyczne usunięcie danych nastąpi później, gdy wykonywana jest operacja głównego zagęszczania.

Atrybuty należące do tej samej grupy kolumn i odpowiadające temu samemu kluczowi są fizycznie przechowywane jako posortowana lista. Każdy atrybut może być nieobecny lub obecny dla każdego klucza, a jeśli atrybut jest nieobecny, nie powoduje to narzutu związanego z przechowywaniem pustych wartości.

Nazwy list i grup kolumn są stałe i mają przejrzysty układ. Na poziomie grupy kolumn ustawiane są parametry takie jak czas życia (TTL) oraz maksymalna ilość przechowywanych wersji. Jeśli różnica między znacznikiem czasu dla danej wersji a czasem bieżącym jest większa niż TTL, wpis jest oznaczany do usunięcia. Jeśli liczba wersji dla danego atrybutu przekroczy maksymalną liczbę wersji, rekord również zostanie oznaczony do usunięcia.

Model danych Hbase można zapamiętać jako dopasowanie klucz-wartość:

<table, RowKey, Column Family, Column, timestamp> -> Value

6.3 Obsługiwane operacje

Lista obsługiwanych operacji w hbase jest dość prosta. Obsługiwane są 4 główne operacje:

  • Umieść : dodaj nowy wpis do hbase. Znacznik czasu tego wpisu można ustawić ręcznie, w przeciwnym razie zostanie on ustawiony automatycznie na aktualny czas.
  • Get : Pobierz dane dla określonego RowKey. Możesz określić Rodzinę Kolumn, z której będziemy pobierać dane oraz liczbę wersji, które chcemy odczytać.
  • Skanuj : czytaj rekordy jeden po drugim. Możesz określić rekord, od którego zaczniemy czytać, rekord do którego będziemy czytać, liczbę rekordów do odczytania, Rodzinę Kolumn, z której będzie wykonywany odczyt oraz maksymalną liczbę wersji dla każdego rekordu.
  • Usuń : zaznacz określoną wersję do usunięcia. Nie będzie fizycznego usunięcia, zostanie ono przełożone do następnego większego zagęszczenia (patrz poniżej).

6.4 Architektura

HBase to rozproszona baza danych, która może działać na dziesiątkach lub setkach fizycznych serwerów, zapewniając nieprzerwane działanie nawet w przypadku awarii niektórych z nich. Dlatego architektura HBase jest dość złożona w porównaniu do klasycznych relacyjnych baz danych.

HBase wykorzystuje do swojej pracy dwa główne procesy:

1. Serwer regionu — obsługuje jeden lub więcej regionów. Region to zakres rekordów odpowiadający określonemu zakresowi kolejnych RowKeys. Każdy region zawiera:

  • Persistent Storage to główny magazyn danych w HBase. Dane są fizycznie przechowywane na HDFS, w specjalnym formacie HFile. Dane w HFile są przechowywane w kolejności posortowanej według RowKey. Jedna para (region, rodzina kolumn) odpowiada co najmniej jednemu HFIle.
  • MemStore - bufor zapisu. Ponieważ dane są przechowywane w HFile d w posortowanej kolejności, aktualizacja HFile dla każdego rekordu jest dość kosztowna. Zamiast tego podczas zapisu dane trafiają do specjalnego obszaru pamięci MemStore, gdzie gromadzą się przez pewien czas. Kiedy MemStore jest wypełniony do pewnej wartości krytycznej, dane są zapisywane do nowego HFile.
  • BlockCache - pamięć podręczna do odczytu. Pozwala znacznie zaoszczędzić czas na danych, które są często odczytywane.
  • Dziennik zapisu z wyprzedzeniem (WAL) . Ponieważ dane są zapisywane w pamięci, istnieje pewne ryzyko utraty danych z powodu awarii. Aby temu zapobiec, wszystkie operacje przed faktyczną realizacją manipulacji są zapisywane w specjalnym pliku dziennika. Pozwala to na odzyskanie danych po każdej awarii.

2. Master Server – główny serwer w klastrze HBase. Mistrz zarządza dystrybucją regionów wśród Serwerów Regionów, prowadzi rejestr regionów, zarządza uruchamianiem regularnych zadań i wykonuje inne przydatne prace.

Do koordynowania działań pomiędzy usługami HBase wykorzystuje Apache ZooKeeper, specjalną usługę przeznaczoną do zarządzania konfiguracjami i synchronizacji usług.

Gdy ilość danych w regionie wzrasta i osiąga określony rozmiar, Hbase rozpoczyna podział, operację dzielącą region na 2. Aby uniknąć ciągłego podziału regionów, można wstępnie ustawić granice regionów i zwiększyć ich maksymalną rozmiar.

Ponieważ dane dla jednego regionu mogą być przechowywane w kilku plikach HF, Hbase okresowo je scala, aby przyspieszyć pracę. Ta operacja jest nazywana zagęszczaniem w Hbase. Zagęszczenia są dwojakiego rodzaju:

  • Niewielkie zagęszczenie . Uruchamia się automatycznie, działa w tle. Ma niski priorytet w porównaniu z innymi operacjami Hbase.
  • Duże zagęszczenie . Jest uruchamiany ręcznie lub po wystąpieniu określonych wyzwalaczy (na przykład przez timer). Ma wysoki priorytet i może znacznie spowolnić klaster. Główne zagęszczenia najlepiej wykonywać w czasie, gdy obciążenie klastra jest niewielkie. Major Compaction usuwa również fizycznie dane wcześniej oznaczone nagrobkiem.

6.5 Sposoby pracy z HBase

Powłoka HBase

Najprostszym sposobem na rozpoczęcie pracy z Hbase jest użycie narzędzia powłoki hbase. Jest dostępny natychmiast po zainstalowaniu hbase na dowolnym węźle klastra hbase.

Powłoka Hbase to konsola jruby z wbudowaną obsługą wszystkich podstawowych operacji Hbase. Poniżej znajduje się przykład tworzenia tabeli użytkowników z dwiema rodzinami kolumn, wykonywania na niej pewnych manipulacji i upuszczania tabeli na końcu w powłoce hbase:

create 'users', {NAME => 'user_profile', VERSIONS => 5}, {NAME => 'user_posts', VERSIONS => 1231231231} 
put 'users', 'id1', 'user_profile:name', 'alexander' 
put 'users', 'id1', 'user_profile:second_name', 'alexander' 
get 'users', 'id1' 
put 'users', 'id1', 'user_profile:second_name', 'kuznetsov' 
get 'users', 'id1' 
get 'users', 'id1', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
put 'users', 'id2', 'user_profile:name', 'vasiliy' 
put 'users', 'id2', 'user_profile:second_name', 'ivanov' 
scan 'users', {COLUMN => 'user_profile:second_name', VERSIONS => 5} 
delete 'users', 'id1', 'user_profile:second_name' 
get 'users', 'id1' 
disable 'users' 
drop 'users'

Natywne API

Podobnie jak większość innych projektów związanych z hadoopem, hbase jest zaimplementowany w Javie, więc natywne API jest dostępne w Javie. Natywny interfejs API jest dość dobrze udokumentowany na oficjalnej stronie internetowej. Oto przykład użycia interfejsu API Hbase zaczerpniętego z tego miejsca:

import java.io.IOException;

import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class MyLittleHBaseClient {
  public static void main(String[] args) throws IOException {
	Configuration config = HBaseConfiguration.create();
	Connection connection = ConnectionFactory.createConnection(config);
	try {
  	Table table = connection.getTable(TableName.valueOf("myLittleHBaseTable"));
  	try {
    	Put p = new Put(Bytes.toBytes("myLittleRow"));
    	p.add(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"),
    	Bytes.toBytes("Some Value"));
    	table.put(p);

    	Get g = new Get(Bytes.toBytes("myLittleRow"));
    	Result r = table.get(g);
    	byte [] value = r.getValue(Bytes.toBytes("myLittleFamily"),
      	Bytes.toBytes("someQualifier"));

    	String valueStr = Bytes.toString(value);
    	System.out.println("GET: " + valueStr);

    	Scan s = new Scan();
    	s.addColumn(Bytes.toBytes("myLittleFamily"), Bytes.toBytes("someQualifier"));
    	ResultScanner scanner = table.getScanner(s);
    	try {
       	for (Result rr = scanner.next(); rr != null; rr = scanner.next()) {
         	System.out.println("Found row: " + rr);
       	}
     	} finally {
       	scanner.close();
     	}
   	} finally {
     	if (table != null) table.close();
   	}
 	} finally {
   	connection.close();
 	}
  }
}

Thrift, REST i wsparcie dla innych języków programowania

Aby pracować z innymi językami programowania, Hbase udostępnia Thrift API i Rest API. Na ich podstawie budowane są klienty dla wszystkich głównych języków programowania: python, PHP, Java Script itp.

6.6 Niektóre cechy pracy z HBase

  1. Hbase integruje się z MapReduce i może być używany jako dane wejściowe i wyjściowe przy użyciu specjalnych TableInputFormat i TableOutputFormat.

  2. Bardzo ważne jest, aby wybrać odpowiedni RowKey. RowKey musi zapewniać dobrą równomierną dystrybucję między regionami, w przeciwnym razie istnieje ryzyko tak zwanych „gorących regionów” — regionów, które są używane znacznie częściej niż inne, co prowadzi do nieefektywnego wykorzystania zasobów systemowych.

  3. Jeśli dane nie są ładowane pojedynczo, ale od razu w dużych partiach, Hbase obsługuje specjalny mechanizm BulkLoad, który pozwala na przesyłanie danych znacznie szybciej niż przy użyciu pojedynczych Putów. BulkLoad to zasadniczo operacja dwuetapowa:

    • Tworzenie HFile bez udziału putów za pomocą specjalnego zadania MapReduce
    • Wstawianie tych plików bezpośrednio do Hbase
  4. Hbase obsługuje wysyłanie swoich metryk do serwera monitorowania Ganglia. Może to być bardzo pomocne podczas administrowania Hbase, aby dotrzeć do sedna problemów z Hbase.

klucz wiersza

RowKey to identyfikator użytkownika, który jest identyfikatorem GUUID, ciągiem specjalnie wygenerowanym, aby był unikalny na całym świecie. Identyfikatory GUUID są rozmieszczone równomiernie, co zapewnia dobrą dystrybucję danych między serwerami.

Rodzina kolumn

Nasza pamięć wykorzystuje dwie rodziny kolumn:

  • dane. Ta grupa kolumn przechowuje dane, które nie są już przydatne do celów reklamowych, takie jak fakt, że użytkownik odwiedził określone adresy URL. TTL dla tej rodziny kolumn jest ustawiony na 2 miesiące, limit liczby wersji to 2000.
  • długie dane. Ta grupa kolumn przechowuje dane, które nie tracą na aktualności w czasie, takie jak płeć, data urodzenia i inne „odwieczne” cechy użytkownika.

głośniki

Każdy typ faktów użytkownika jest przechowywany w osobnej kolumnie. Na przykład kolumna Data:_v przechowuje adresy URL odwiedzane przez użytkownika, a kolumna LongData:gender przechowuje płeć użytkownika.

Znacznik czasu tego faktu jest przechowywany jako znacznik czasu. Na przykład w kolumnie Dane:_v sygnatura czasowa to czas, w którym użytkownik odwiedził określony adres URL.

Ta struktura przechowywania danych użytkownika bardzo dobrze pasuje do naszego wzorca użytkowania i pozwala szybko aktualizować dane użytkownika, szybko uzyskać wszystkie niezbędne informacje o użytkownikach, a za pomocą MapReduce szybko przetwarzać dane o wszystkich użytkownikach jednocześnie.

6.7 Alternatywy

HBase jest dość skomplikowany w administrowaniu i użytkowaniu, więc przed użyciem HBase warto przyjrzeć się alternatywom:

  • relacyjne bazy danych . Bardzo dobra alternatywa, szczególnie w przypadku, gdy dane mieszczą się na jednej maszynie. Także przede wszystkim warto pomyśleć o relacyjnych bazach danych w przypadku, gdy ważne są transakcje indeksów innych niż podstawowy.

  • Przechowywanie klucz-wartość . Magazyny, takie jak Redis i Aerospike, są lepiej dostosowane, gdy potrzebne są opóźnienia, a przetwarzanie wsadowe jest mniej ważne.

  • Pliki i ich przetwarzanie za pomocą MapReduce . Jeśli dane są tylko dodawane i rzadko aktualizowane/zmieniane, lepiej nie używać HBase, tylko przechowywać dane w plikach. Aby uprościć pracę z plikami, możesz użyć narzędzi takich jak Hive, Pig i Impala.

Zastosowanie HBase jest uzasadnione, gdy:

  • Danych jest dużo i nie mieszczą się one na jednym komputerze/serwerze
  • Dane są często aktualizowane i usuwane
  • W danych istnieje wyraźny „klucz”, z którym wygodnie jest powiązać wszystko inne
  • Potrzebujesz przetwarzania wsadowego
  • Potrzebujesz losowego dostępu do danych za pomocą określonych kluczy