Dzień dobry! Nazywam się Danil Lipovoy, nasz zespół w Sbertech zaczął używać HBase jako magazynu danych operacyjnych. W trakcie studiowania go zgromadziliśmy doświadczenie, które chcieliśmy usystematyzować i opisać (mamy nadzieję, że wielu uzna to za przydatne). Wszystkie poniższe eksperymenty zostały przeprowadzone z wersjami HBase 1.2.0-cdh5.14.2 i 2.0.0-cdh6.0.0-beta1.
- Architektura ogólna
- Zapisywanie danych do HBASE
- Odczyt danych z HBASE
- Buforowanie danych
- Przetwarzanie danych wsadowych MultiGet/MultiPut
- Strategia podziału tabeli na regiony (rozlewanie)
- Tolerancja błędów, kompaktowość i lokalizacja danych
- Ustawienia i wydajność
- Test naprężeń
- odkrycia
1. Ogólna architektura

Zapasowy Master nasłuchuje bicia serca aktywnego ZooKeepera na węźle i przejmuje funkcje Mastera w przypadku jego zniknięcia.
2. Zapisywanie danych do HBASE
Najpierw rozważmy najprostszy przypadek — zapisanie obiektu klucz-wartość do tabeli za pomocą put(rowkey). Klient musi najpierw dowiedzieć się, gdzie znajduje się Root Region Server (RRS), który przechowuje tabelę hbase:meta. Otrzymuje te informacje od ZooKeeper. Następnie uzyskuje dostęp do RRS i odczytuje tabelę hbase:meta, z której wyodrębnia informacje o tym, który RegionServer (RS) odpowiada za przechowywanie danych dla danego rowkey w tabeli, którą jest zainteresowany. Do dalszego użytku tabela meta jest buforowana przez klienta, więc kolejne żądania są szybsze, bezpośrednio do RS.
Następnie RS, po otrzymaniu żądania, najpierw zapisuje je do WriteAheadLog (WAL), co jest konieczne do odzyskania danych w przypadku awarii. Następnie zapisuje dane do MemStore. Jest to bufor w pamięci, który zawiera posortowany zestaw kluczy dla danego regionu. Tabelę można podzielić na regiony (partycje), z których każdy zawiera nienakładający się na siebie zestaw kluczy. Pozwala to na wyższą wydajność poprzez umieszczenie regionów na różnych serwerach. Jednak pomimo oczywistości tego stwierdzenia, zobaczymy później, że nie działa to we wszystkich przypadkach.
Po umieszczeniu rekordu w MemStore klient otrzymuje odpowiedź, że rekord został pomyślnie zapisany. W rzeczywistości jest on przechowywany tylko w buforze i zostanie zapisany na dysku dopiero po upływie określonego czasu lub po wypełnieniu go nowymi danymi.

Gdy wykonywana jest operacja „Delete”, nie następuje żadne fizyczne usunięcie danych. Są one po prostu oznaczane jako usunięte, a samo zniszczenie następuje w momencie wywołania głównej funkcji kompaktowej, która jest opisana bardziej szczegółowo w akapicie 7.
Pliki HFile są przechowywane w HDFS i od czasu do czasu uruchamiany jest niewielki proces kompaktowy, który po prostu skleja małe pliki w większe bez usuwania czegokolwiek. Z czasem staje się to problemem, który ujawnia się tylko podczas odczytu danych (wrócimy do tego nieco później).
Oprócz opisanego powyżej procesu ładowania istnieje o wiele wydajniejsza procedura, która jest chyba najmocniejszą stroną tej bazy danych - BulkLoad. Polega ona na tym, że samodzielnie formujemy pliki HFiles i umieszczamy je na dysku, co pozwala na doskonałe skalowanie i osiąganie całkiem przyzwoitych prędkości. Tak naprawdę ograniczeniem tutaj nie jest HBase, ale możliwości sprzętu. Poniżej przedstawiono wyniki ładowania na klastrze składającym się z 16 RegionServers i 16 NodeManager YARN (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki), wersja HBase 1.2.0-cdh5.14.2.

Tutaj widać, że zwiększając liczbę partycji (regionów) w tabeli, a także wykonawców Spark, uzyskujemy wzrost szybkości ładowania. Szybkość zależy również od wolumenu rekordu. Duże bloki dają wzrost pomiaru MB/s, małe liczby wstawianych rekordów na jednostkę czasu, przy założeniu, że wszystkie inne czynniki są równe.
Możesz również uruchomić pobieranie do dwóch tabel jednocześnie i uzyskać podwojenie prędkości. Poniżej możesz zobaczyć, że zapisywanie bloków 10 KB do dwóch tabel jednocześnie odbywa się z prędkością około 600 MB/s każdy (łącznie 1275 MB/s), co pokrywa się z prędkością zapisywania do jednej tabeli wynoszącą 623 MB/s (patrz #11 powyżej)

Ale drugie uruchomienie z rekordami 50 KB pokazuje, że prędkość ładowania rośnie nieznacznie, co wskazuje, że zbliżamy się do wartości granicznych. Należy pamiętać, że na samym HBASE praktycznie nie ma obciążenia, wszystko, co wymaga się od niego, to najpierw podać dane z hbase:meta, a po wykonaniu kopii zapasowej HFiles zresetować dane BlockCache i zapisać bufor MemStore na dysku, jeśli nie jest pusty.
3. Odczyt danych z HBASE
Jeśli założymy, że wszystkie informacje z hbase:meta są już w kliencie (patrz punkt 2), to żądanie trafia bezpośrednio do RS, gdzie przechowywany jest wymagany klucz. Najpierw wyszukiwanie jest wykonywane w MemCache. Niezależnie od tego, czy są tam dane, czy nie, wyszukiwanie jest również wykonywane w buforze BlockCache i, jeśli to konieczne, w HFiles. Jeśli dane zostały znalezione w pliku, to są umieszczane w BlockCache i zostaną zwrócone szybciej podczas następnego żądania. Wyszukiwanie w HFile jest stosunkowo szybkie dzięki zastosowaniu filtru Blooma, tzn. po odczytaniu niewielkiej ilości danych natychmiast ustala, czy ten plik zawiera wymagany klucz, a jeśli nie, to przechodzi do następnego.

Otrzymawszy dane z tych trzech źródeł, RS tworzy odpowiedź. W szczególności może przesłać kilka znalezionych wersji obiektu na raz, jeśli klient zażądał wersjonowania.
4. Buforowanie danych
Bufory MemStore i BlockCache zajmują do 80% przydzielonej pamięci RS na stosie (reszta jest zarezerwowana dla zadań obsługi RS). Jeśli typowy tryb użytkowania jest taki, że procesy zapisują i natychmiast odczytują te same dane, wówczas sensowne jest zmniejszenie BlockCache i zwiększenie MemStore, ponieważ gdy dane do pamięci podręcznej nie są zapisywane do odczytu, wówczas BlockCache będzie używane rzadziej. Bufor BlockCache składa się z dwóch części: LruBlockCache (zawsze na stosie) i BucketCache (zwykle poza stosem lub na dysku SSD). BucketCache należy używać, gdy występuje wiele żądań odczytu i nie mieszczą się one w LruBlockCache, co prowadzi do aktywnej pracy Garbage Collectora. Jednocześnie nie należy oczekiwać radykalnego wzrostu wydajności dzięki wykorzystaniu pamięci podręcznej do odczytu, ale wrócimy do tego w akapicie 8.

Dla całego RS istnieje jeden BlockCache, a każda tabela ma swój własny MemStore (jeden dla każdej rodziny kolumn).
jak Teoretycznie, podczas zapisywania danych do pamięci podręcznej, nie docierają one tam i rzeczywiście, takie parametry jak CACHE_DATA_ON_WRITE dla tabeli i „Cache DATA on Write” dla RS są ustawione na false. Jednak w praktyce, jeśli zapiszesz dane do MemStore, a następnie opróżnisz je na dysk (czyszcząc je), a następnie usuniesz wynikowy plik, to wykonując żądanie get, pomyślnie otrzymamy dane. Co więcej, nawet jeśli całkowicie wyłączysz BlockCache i wypełnisz tabelę nowymi danymi, a następnie uzyskasz reset MemStore na dysk, usuniesz je i zażądasz z innej sesji, nadal zostaną one pobrane skądś. Tak więc HBase przechowuje nie tylko dane, ale także tajemnicze tajemnice.
hbase(main):001:0> create 'ns:magic', 'cf'
Created table ns:magic
Took 1.1533 seconds
hbase(main):002:0> put 'ns:magic', 'key1', 'cf:c', 'try_to_delete_me'
Took 0.2610 seconds
hbase(main):003:0> flush 'ns:magic'
Took 0.6161 seconds
hdfs dfs -mv /data/hbase/data/ns/magic/* /tmp/trash
hbase(main):002:0> get 'ns:magic', 'key1'
cf:c timestamp=1534440690218, value=try_to_delete_me
Parametr „Cache DATA on Read” jest ustawiony na false. Jeśli masz jakieś pomysły, możesz je omówić w komentarzach.
5. Przetwarzanie danych wsadowych MultiGet/MultiPut
Przetwarzanie pojedynczych żądań (Get/Put/Delete) jest dość kosztowną operacją, dlatego należy je połączyć w Listę lub Listę, jeśli to możliwe, co pozwala uzyskać znaczny wzrost wydajności. Dotyczy to zwłaszcza operacji zapisu, ale istnieje następująca pułapka podczas odczytu. Poniższy wykres pokazuje czas odczytu 50 000 rekordów z MemStore. Odczyt został wykonany w jednym wątku, a oś pozioma pokazuje liczbę kluczy w żądaniu. Tutaj widać, że przy zwiększeniu do tysiąca kluczy w jednym żądaniu czas wykonania spada, tj. wzrasta prędkość. Jednak przy domyślnie włączonym trybie MSLAB po przekroczeniu tego progu zaczyna się radykalny spadek wydajności, a im większa objętość danych w rekordzie, tym dłuższy czas działania.

Testy przeprowadzono na maszynie wirtualnej 8-rdzeniowej, wersja HBase 2.0.0-cdh6.0.0-beta1.
Tryb MSLAB został zaprojektowany w celu zmniejszenia fragmentacji sterty, która występuje z powodu mieszania danych nowych i starych generacji. Jako rozwiązanie problemu, gdy MSLAB jest włączony, dane są umieszczane w stosunkowo małych komórkach (fragmentach) i przetwarzane w porcjach. W rezultacie, gdy objętość w żądanym pakiecie danych przekracza przydzielony rozmiar, wydajność gwałtownie spada. Z drugiej strony, wyłączenie tego trybu jest również niepożądane, ponieważ doprowadzi do zatrzymań z powodu GC w okresach intensywnej pracy z danymi. Dobrym rozwiązaniem jest zwiększenie rozmiaru komórki, w przypadku aktywnego zapisu przez put jednocześnie z odczytem. Warto zauważyć, że problem nie występuje, jeśli po zapisie wykonasz polecenie flush, które resetuje MemStore na dysku, lub jeśli ładowanie jest wykonywane za pomocą BulkLoad. Poniższa tabela pokazuje, że żądania z MemStore większych danych (i tej samej ilości) prowadzą do spowolnienia. Jednak zwiększenie rozmiaru fragmentu przywraca czas przetwarzania do normy.

Oprócz zwiększenia rozmiaru fragmentu, pomaga podział danych według regionów, tj. podział tabeli. Powoduje to mniejszą liczbę żądań przychodzących do każdego regionu, a jeśli mieszczą się w komórce, odpowiedź pozostaje dobra.
6. Strategia podziału tabeli na regiony (rozlewanie)
Ponieważ HBase jest magazynem klucz-wartość, a partycjonowanie odbywa się według klucza, niezwykle ważne jest dzielenie danych równomiernie na wszystkie regiony. Na przykład partycjonowanie takiej tabeli na trzy części spowoduje podzielenie danych na trzy regiony:

Może to czasami prowadzić do gwałtownego spowolnienia, jeżeli dane ładowane później to np. długie wartości, które przeważnie zaczynają się od tej samej liczby, na przykład:
1000001
1000002
...
1100003
Ponieważ klucze są przechowywane jako tablica bajtów, wszystkie będą zaczynać się w ten sam sposób i będą należeć do tego samego regionu #1, który przechowuje ten zakres kluczy. Istnieje kilka strategii partycjonowania:
HexStringSplit – konwertuje klucz na ciąg z kodowaniem szesnastkowym w zakresie „00000000” => „FFFFFFFF” i uzupełnieniem zerami z lewej strony.
UniformSplit – zamienia klucz na tablicę bajtów z kodowaniem szesnastkowym w zakresie „00” => „FF” i uzupełnieniem zerami po prawej stronie.
Ponadto możesz określić dowolny zakres lub zestaw kluczy do podziału i skonfigurować automatyczne dzielenie. Jednak jednym z najprostszych i najskuteczniejszych podejść jest UniformSplit i użycie konkatenacji haszującej, na przykład starszej pary bajtów z uruchomienia klucza przez funkcję CRC32(rowkey) i samego rowkey:
hash + klucz wiersza
Następnie wszystkie dane zostaną równomiernie rozłożone w regionach. Podczas odczytu pierwsze dwa bajty są po prostu odrzucane, a oryginalny klucz pozostaje. RS kontroluje również ilość danych i kluczy w regionie i automatycznie dzieli je na części, gdy limity zostaną przekroczone.
7. Tolerancja błędów i lokalizacja danych
Ponieważ tylko jeden region odpowiada za każdy zestaw kluczy, rozwiązaniem problemów związanych z awariami RS lub wycofaniem z eksploatacji jest przechowywanie wszystkich niezbędnych danych w HDFS. Kiedy RS ulega awarii, master wykrywa to poprzez brak sygnału heartbeat na węźle ZooKeeper. Następnie przypisuje obsługiwany region innemu RS, a ponieważ pliki HFiles są przechowywane w rozproszonym systemie plików, nowy właściciel je odczytuje i kontynuuje obsługę danych. Jednak ponieważ część danych może znajdować się w MemStore i nie miała czasu, aby dostać się do plików HFiles, WAL jest używany do przywracania historii operacji, które są również przechowywane w HDFS. Po wdrożeniu zmian, RS jest w stanie odpowiedzieć na żądania, ale ruch ten prowadzi do tego, że część danych i obsługujących je procesów trafia na różne węzły, tj. zmniejsza się lokalizacja.
Rozwiązaniem problemu jest major compaction – procedura ta przenosi pliki do węzłów za nie odpowiedzialnych (gdzie znajdują się ich regiony), w wyniku czego obciążenie sieci i dysków gwałtownie wzrasta podczas tej procedury. Jednak dostęp do danych jest zauważalnie przyspieszony w przyszłości. Ponadto major_compacion łączy wszystkie pliki HFiles w jeden plik w obrębie regionu, a także czyści dane w zależności od ustawień tabeli. Na przykład można ustawić liczbę wersji obiektu, które muszą zostać zapisane lub jego czas życia, po którym obiekt jest fizycznie usuwany.
Ta procedura może mieć bardzo pozytywny wpływ na wydajność HBase. Poniższy rysunek pokazuje, jak wydajność uległa pogorszeniu w wyniku aktywnego zapisu danych. Tutaj możesz zobaczyć, jak 40 wątków zapisywało i 40 wątków jednocześnie odczytywało dane do jednej tabeli. Wątki zapisu tworzą coraz więcej plików HFile, które są odczytywane przez inne wątki. W rezultacie coraz więcej danych musi zostać usuniętych z pamięci, a ostatecznie GC zaczyna działać, co praktycznie paraliżuje całą pracę. Uruchomienie poważnej kompresji doprowadziło do oczyszczenia powstałych blokad i przywrócenia wydajności.

Test przeprowadzono na 3 DataNodes i 4 RS (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki). Wersja HBase 1.2.0-cdh5.14.2
Warto zauważyć, że główne zagęszczanie zostało uruchomione na „żywej” tabeli, do której dane były aktywnie zapisywane i odczytywane. W sieci pojawiło się oświadczenie, że może to prowadzić do nieprawidłowej odpowiedzi podczas odczytu danych. Aby to sprawdzić, uruchomiono proces, który wygenerował nowe dane i zapisał je do tabeli. Następnie natychmiast odczytał i sprawdził, czy otrzymana wartość zgadza się z zapisaną. Podczas działania tego procesu główne zagęszczanie zostało uruchomione około 200 razy i nie odnotowano ani jednej awarii. Być może problem występuje rzadko i tylko przy dużym obciążeniu, więc bezpieczniej jest rutynowo zatrzymywać procesy zapisu i odczytu oraz wykonywać czyszczenie, zapobiegając takim spadkom GC.
Ponadto, główna kompresja nie wpływa na stan MemStore. Aby zapisać go na dysku i skompaktować, należy użyć funkcji flush (connection.getAdmin().flush(TableName.valueOf(tblName))).
8. Ustawienia i wydajność
Jak wspomniano, HBase jest najbardziej skuteczny, gdy nie musi nic robić, np. BulkLoad. Dotyczy to większości systemów i osób. Jednak jest bardziej odpowiedni do ładowania danych zbiorczych w dużych blokach, podczas gdy jeśli proces wymaga wielu równoczesnych żądań odczytu i zapisu, używane są polecenia Get i Put opisane powyżej. Aby określić optymalne parametry, wykonano przebiegi z różnymi kombinacjami parametrów i ustawień tabeli:
- Jednocześnie uruchomiono 10 wątków 3 razy z rzędu (nazwijmy to blokiem wątków).
- Uśredniano czas działania wszystkich wątków w bloku i stanowił on końcowy wynik działania bloku.
- Wszystkie wątki pracowały z tą samą tabelą.
- Przed uruchomieniem każdego bloku wątków przeprowadzano gruntowną kompresję.
- Każdy blok wykonywał tylko jedną z następujących operacji:
- Umieścić
-Dostawać
— Zdobądź+Połóż
- Każdy blok wykonał 50 000 powtórzeń swojej operacji.
- Rozmiar rekordu w bloku wynosi 100 bajtów, 1000 bajtów lub 10000 bajtów (losowo).
- Bloki uruchamiano z różną liczbą żądanych kluczy (jeden lub 10).
- Bloki zostały uruchomione z różnymi ustawieniami tabeli. Parametry zostały zmienione:
— BlockCache = włączony lub wyłączony
— Rozmiar bloku = 65 KB lub 16 KB
— Partycje = 1, 5 lub 30
— MSLAB = włączony lub wyłączony
Blok wygląda następująco:
a. Tryb MSLAB został włączony/wyłączony.
b. Utworzono tabelę, dla której ustawiono następujące parametry: BlockCache = true/none, BlockSize = 65/16 Kb, Partitions = 1/5/30.
c. Ustawiono kompresję GZ.
d. Uruchomiono 10 wątków jednocześnie, wykonując 1/10 operacji put/get/get+put w tej tabeli z rekordami o rozmiarze 100/1000/10000 bajtów, wykonując 50 000 żądań z rzędu (klucze losowe).
e. Punkt d powtórzono trzy razy.
f. Uśredniono czas działania wszystkich wątków.
Przetestowano wszystkie możliwe kombinacje. Można przewidzieć, że prędkość spadnie wraz ze wzrostem rozmiaru rekordu lub że wyłączenie buforowania spowolni. Jednak celem było zrozumienie stopnia i znaczenia wpływu każdego parametru, więc zebrane dane zostały wprowadzone do wejścia funkcji regresji liniowej, co umożliwia oszacowanie niezawodności za pomocą statystyki t. Poniżej przedstawiono wyniki bloków wykonujących operacje Put. Pełny zestaw kombinacji to 2 * 2 * 3 * 2 * 3 = 144 opcje + 72, ponieważ niektóre zostały wykonane dwukrotnie. Zatem w sumie wykonano 216 przebiegów:

Testy przeprowadzono na mini-klastrze składającym się z 3 DataNodes i 4 RS (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki). Wersja HBase 1.2.0-cdh5.14.2.
Największą prędkość wprowadzania danych, wynoszącą 3.7 s, uzyskano przy wyłączonym trybie MSLAB, na tabeli z jedną partycją, z włączonym BlockCache, BlockSize = 16, z rekordami 100-bajtowymi, 10 sztukami na partię.
Najniższą prędkość wprowadzania danych, wynoszącą 82.8 s, uzyskano przy włączonym trybie MSLAB, na tabeli z jedną partycją, z włączoną funkcją BlockCache, BlockSize = 16 i rekordami o rozmiarze 10000 1 bajtów (po XNUMX rekordzie).
Teraz spójrzmy na model. Widzimy dobrą jakość modelu według R2, ale jest absolutnie jasne, że ekstrapolacja jest tutaj przeciwwskazana. Rzeczywiste zachowanie systemu przy zmianie parametrów nie będzie liniowe, ten model jest potrzebny nie do prognoz, ale do zrozumienia, co się wydarzyło w określonych parametrach. Na przykład tutaj widzimy według kryterium Studenta, że parametry BlockSize i BlockCache nie mają znaczenia dla operacji Put (która jest generalnie dość przewidywalna):

Ale fakt, że zwiększenie liczby partycji prowadzi do spadku wydajności jest nieco nieoczekiwany (widzieliśmy już pozytywny efekt zwiększenia liczby partycji za pomocą BulkLoad), chociaż jest zrozumiały. Po pierwsze, do przetwarzania konieczne jest utworzenie żądań do 30 regionów zamiast jednego, a objętość danych nie jest taka, aby dawało to zysk. Po drugie, całkowity czas działania jest określany przez najwolniejszy RS, a ponieważ liczba DataNode jest mniejsza niż liczba RS, niektóre regiony mają zerową lokalność. Cóż, spójrzmy na pierwszą piątkę:

Teraz oceńmy wyniki wykonania bloków Get:

Liczba partycji straciła na znaczeniu, co prawdopodobnie wynika z faktu, że dane są dobrze buforowane, a bufor odczytu jest najważniejszym (statystycznie) parametrem. Naturalnie, zwiększenie liczby wiadomości w żądaniu jest również bardzo przydatne dla wydajności. Najlepsze wyniki:

No cóż, na koniec przyjrzyjmy się modelowi bloku, który najpierw wykonał polecenie get, a następnie put:

Tutaj wszystkie parametry są istotne. I wyniki liderów:

9. Testowanie obciążeniowe
No cóż, w końcu uruchomimy mniej lub bardziej przyzwoity ładunek, ale zawsze ciekawiej jest, gdy jest z czym porównać. Na stronie DataStax, głównego dewelopera Cassandry, jest NT szeregu magazynów NoSQL, w tym HBase w wersji 0.98.6-1. Ładowanie odbywało się za pomocą 40 wątków, rozmiar danych 100 bajtów, dyski SSD. Wyniki testowania operacji Read-Modify-Write pokazały następujące rezultaty.

O ile rozumiem, odczyt odbywał się w blokach po 100 rekordów, a dla 16 węzłów HBase test DataStax wykazał wydajność na poziomie 10 tysięcy operacji na sekundę.
Na szczęście nasz klaster ma również 16 węzłów, ale nie jest już tak „szczęśliwie”, że każdy ma 64 rdzenie (wątki), podczas gdy test DataStax ma ich tylko 4. Z drugiej strony oni mają dyski SSD, podczas gdy my mamy HDD i nowszą wersję HBase, a wykorzystanie CPU podczas obciążenia praktycznie nie wzrosło znacząco (wizualnie o 5-10 procent). Spróbujemy jednak uruchomić na takiej konfiguracji. Domyślne ustawienia tabeli, odczyt odbywa się w zakresie kluczy od 0 do 50 milionów losowo (czyli zasadniczo za każdym razem nowy). Tabela ma 50 milionów rekordów, podzielonych na 64 partycje. Klucze są hashowane za pomocą crc32. Domyślne ustawienia tabeli, MSLAB jest włączony. Uruchomienie 40 wątków, każdy wątek odczytuje zestaw 100 losowych kluczy i natychmiast zapisuje wygenerowane 100 bajtów dla tych kluczy z powrotem.

Stand: 16 DataNode i 16 RS (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki). Wersja HBase 1.2.0-cdh5.14.2.
Średni wynik jest bliższy 40 tysiącom operacji na sekundę, co jest znacznie lepsze niż w teście DataStax. Jednak na potrzeby eksperymentu można nieco zmienić warunki. Jest mało prawdopodobne, aby cała praca była wykonywana wyłącznie z jedną tabelą i tylko z unikalnymi kluczami. Załóżmy, że istnieje „gorący” zestaw kluczy, który generuje główne obciążenie. Dlatego spróbujemy utworzyć obciążenie większych rekordów (10 KB), również w partiach po 100, w 4 różnych tabelach i ograniczyć zakres żądanych kluczy do 50 tysięcy. Poniższy wykres przedstawia uruchomienie 40 wątków, każdy wątek odczytuje zestaw 100 kluczy i natychmiast zapisuje losowe 10 KB z powrotem dla tych kluczy.

Stand: 16 DataNode i 16 RS (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki). Wersja HBase 1.2.0-cdh5.14.2.
Podczas ładowania, główne zagęszczanie było uruchamiane kilka razy, jak pokazano powyżej, bez tej procedury wydajność będzie stopniowo spadać, ale podczas wykonywania występuje również dodatkowe obciążenie. Obniżki są spowodowane różnymi przyczynami. Czasami wątki kończyły pracę i podczas ponownego uruchamiania następowała przerwa, czasami aplikacje innych firm tworzyły obciążenie klastra.
Natychmiastowe odczytywanie i zapisywanie jest jednym z najtrudniejszych scenariuszy dla HBase. Jeśli wykonujesz tylko małe żądania put, na przykład 100 bajtów, łącząc je w partie po 10-50 tysięcy sztuk, możesz uzyskać setki tysięcy operacji na sekundę, a to samo dotyczy żądań read-only. Warto zauważyć, że wyniki są radykalnie lepsze niż te uzyskane przez DataStax, szczególnie ze względu na żądania w blokach po 50 tysięcy.

Stand: 16 DataNode i 16 RS (CPU Xeon E5-2680 v4 @ 2.40GHz * 64 wątki). Wersja HBase 1.2.0-cdh5.14.2.
10. Wnioski
Ten system jest dość elastyczny w konfiguracji, ale wpływ dużej liczby parametrów jest nadal nieznany. Niektóre z nich zostały przetestowane, ale nie zostały uwzględnione w wynikowym zestawie testowym. Na przykład wstępne eksperymenty wykazały nieistotne znaczenie takiego parametru jak DATA_BLOCK_ENCODING, który koduje informacje za pomocą wartości z sąsiednich komórek, co jest całkiem zrozumiałe w przypadku danych generowanych losowo. W przypadku użycia dużej liczby powtarzających się obiektów zysk może być znaczny. Ogólnie rzecz biorąc, można powiedzieć, że HBase sprawia wrażenie dość poważnej i przemyślanej bazy danych, która może być dość produktywna podczas pracy z dużymi blokami danych. Zwłaszcza jeśli możliwe jest rozłożenie w czasie procesów odczytu i zapisu.
Jeśli coś nie zostało wystarczająco ujawnione w Twojej opinii, jestem gotowy powiedzieć Ci więcej szczegółów. Zapraszamy do dzielenia się swoimi doświadczeniami lub dyskusji, jeśli się z czymś nie zgadzasz.
Źródło: www.habr.com
