6.1 Хто і навіщо вигадав HBase
У цій лекції ми поговоримо про такий чудовий інструмент як Hbase, який останнім часом завоював велику популярність: наприклад, Facebook використовує його як основу своєї системи обміну повідомлень, а це вже говорить багато про що.
У лекції розкажемо про концепцію Big Table та її вільну реалізацію, особливості роботи та відмінність як від класичних реляційних баз даних (таких як MySQL та Oracle), так і key-value сховищ, таких як Redis, Aerospike і memcached. Як завжди, почнемо з історії питання. Як і багато інших проєктів з області BigData, Hbase зародилася з концепції, розробленої в Google. Принципи, що лежать в основі Hbase, були описані в статті Bigtable: A Distributed Storage System for Structured Data.
Як ми вже розглядали в минулих лекціях, звичайні файли досить непогано підходять для пакетної обробки даних з використанням парадигми MapReduce. З іншого боку, інформацію, що зберігається у файлах, досить незручно оновлювати; файли також не мають можливості довільного доступу. Для швидкої та зручної роботи з довільним доступом є клас nosql-систем типу key-value storage, таких як Aerospike, Redis, Couchbase, Memcached. Однак зазвичай у цих системах дуже незручна пакетна обробка даних. Hbase є спробою об'єднання зручності пакетної обробки і зручності оновлення і довільного доступу.
2. Модель даних
HBase — це розподілена, колонково-орієнтована, мультиверсійна база типу «ключ-значення».
- Дані організовані в таблиці, проіндексовані первинним ключем, який у Hbase називається RowKey.
- Для кожного RowKey ключа може зберігатися необмежений набір атрибутів (або колонок).
- Колонки організовані в групи колонок, які називають Column Family. Як правило, в одну Column Family об'єднують колонки, для яких однакові патерн використання та зберігання.
- Для кожного атрибута може зберігатися кілька різних версій. Різні версії мають різний timestamp.
Записи фізично зберігаються у відсортованому за RowKey порядку. Водночас дані, що відповідають різним Column Family, зберігаються окремо, що дозволяє при необхідності читати дані тільки з потрібного сімейства колонок.
Під час видалення певного атрибуту фізично він відразу не видаляється, а лише маркується спеціальним прапорцем tombstone. Фізичне видалення даних відбудеться пізніше при виконанні операції Major Compaction.
Атрибути, що належать одній групі колонок і відповідають одному ключу, фізично зберігаються як відсортований список. Будь-який атрибут може бути відсутнім або бути присутнім для кожного ключа, при цьому якщо атрибут відсутній, це не викликає накладних витрат на зберігання порожніх значень.
Список та назви груп колонок фіксований і має чітку схему. На рівні групи колонок встановлюються такі параметри як time to live (TTL) і максимальна кількість версій, що зберігаються. Якщо різниця між timestamp для певної версії і поточним часом більше TTL — запис позначається для видалення. Якщо кількість версій для певного атрибуту перевищила максимальну кількість версій, запис також позначається для видалення.
Модель даних Hbase можна запам'ятати, як відповідність ключ значення:
<table, RowKey, Column Family, Column, timestamp> -> Value
6.3 Підтримувані операції
Список підтримуваних операцій у hbase дуже простий. Підтримуються 4 основні операції:
- Put: додати новий запис до hbase. Timestamp цього запису може бути заданий руками, інакше він буде встановлений автоматично як поточний час.
- Get: отримати дані щодо певного RowKey. Можна вказати Column Family, з якої будемо брати дані та кількість версій, які хочемо прочитати.
- Scan: читати записи по черзі. Можна вказати запис з яким починаємо читати, запис до якого читати, кількість записів, які необхідно вважати, Column Family з якої буде проводитися читання та максимальна кількість версій для кожного запису.
- Delete: позначити певну версію для видалення. Фізичного видалення при цьому не відбудеться, воно буде відкладено до наступного Major Compaction (див. нижче).
4. Архітектура
HBase є розподіленою базою даних, яка може працювати на десятках і сотнях фізичних серверів, забезпечуючи безперебійну роботу навіть у разі виходу з ладу деяких з них. Тому архітектура HBase досить складна в порівнянні з класичними реляційними базами даних.
HBase для своєї роботи використовує два основні процеси:
1. Region Server — обслуговує один або кілька регіонів. Регіон — це діапазон записів, що відповідають певному діапазону RowKey, що йдуть поспіль. Кожен регіон містить:
- Persistent Storage — основне сховище даних у HBase. Дані фізично зберігаються на HDFS у спеціальному форматі HFile. Дані HFile зберігаються в відсортованому за RowKey порядку. Одній парі (регіон, column family) відповідає щонайменше один HFIle.
- MemStore — буфер для запису. Так як дані зберігаються в HFile у відсортованому порядку — оновлювати HFile на кожен запис досить дорого. Натомість дані під час запису потрапляють у спеціальну область пам'яті MemStore, де накопичуються деякий час. У разі заповнення MemStore до певного критичного значення дані записуються до нового HFile.
- BlockCache — кеш для читання. Дозволяє суттєво економити час на даних, які читаються часто.
- Write Ahead Log (WAL). Оскільки дані під час запису потрапляють у memstore, існує певний ризик втрати даних через збій. Для того щоб цього не відбулося, всі операції перед здійсненням маніпуляцій потрапляють до спеціального лог-файлу. Це дозволяє відновити дані після будь-якого збою.
2. Master Server — головний сервер у кластері HBase. Master керує розподілом регіонів за Region Server-ами, веде реєстр регіонів, керує запусками регулярних завдань та робить іншу корисну роботу.
Для координації дій між сервісами HBase використовує Apache ZooKeeper, спеціальний сервіс, призначений для керування конфігураціями та синхронізацією сервісів.
Під час збільшення кількості даних у регіоні та досягненні ним певного розміру Hbase запускає split: операцію, що розбиває регіон на 2. Щоб уникнути постійних поділів регіонів, можна заздалегідь вказати межі регіонів і збільшити їх максимальний розмір.
Оскільки дані по одному регіону можуть зберігатися в декількох HFile, для прискорення роботи Hbase періодично їх зливає воєдино. Ця операція в Hbase називається compaction. Compaction-и бувають двох видів:
- Minor Compaction. Запускається автоматично, виконується у фоновому режимі. Має низький пріоритет у порівнянні з іншими операціями Hbase.
- Major Compaction. Запускається руками або після спрацювання певних тригерів (наприклад за таймером). Має високий пріоритет та може суттєво уповільнити роботу кластера. Major Compaction-и краще робити під час коли навантаження на кластер невелике. Під час Major Compaction також відбувається фізичне видалення даних, рано значених міткою tombstone.
5. Способи роботи з HBase
HBase Shell
Найпростіший спосіб розпочати роботу з Hbase — скористатися утилітою hbase shell. Вона доступна відразу після встановлення hbase на будь-якій ноді кластера hbase.
Hbase shell являє собою jruby-консоль із вбудованою підтримкою всіх основних операцій для роботи з Hbase. Нижче наведено приклад створення таблиці users з двома column family, виконання деяких маніпуляцій з нею та видалення таблиці в кінці на мові hbase shell:
create 'users', {NAME => 'user_profile', VERSIONS => 5}, {NAME => 'user_posts', VERSIONS => 1231231231}
put 'users', 'id1', 'user_profile:name', 'olexandr'
put 'users', 'id1', 'user_profile:second_name', 'olexandr'
get 'users', 'id1'
put 'users', 'id1', 'user_profile:second_name', 'kuznietsov'
get 'users', 'id1'
get 'users', 'id1', {COLUMN => 'user_profile:second_name', VERSIONS => 5}
put 'users', 'id2', 'user_profile:name', 'vasyl'
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'
Native API
Як і більшість інших hadoop-related проєктів, hbase реалізований мовою Java, тому і нативний api доступний мовою Java. Native API досить непогано документований на офіційному сайті. Ось приклад використання Hbase API взятий звідти:
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 та підтримка інших мов програмування
Для роботи з іншими мов програмування Hbase надає Thrift API та Rest API. На їх основі побудовані клієнти для всіх основних мов програмування: python, PHP, Java Script тощо.
6. Деякі особливості роботи з HBase
Hbase «з коробки» інтегрується з MapReduce, і може бути використана як вхідні та вихідні дані за допомогою спеціальних TableInputFormat і TableOutputFormat.
Дуже важливо правильно обрати RowKey. RowKey повинен забезпечувати хороший рівномірний розподіл за регіонами, бо в іншому випадку є ризик виникнення так званих «гарячих регіонів» — регіонів, які використовуються набагато частіше за інші, що призводить до неефективного використання ресурсів системи.
Якщо дані заливаються не поодиноко, а одразу великими пачками, Hbase підтримує спеціальний механізм BulkLoad, який дозволяє заливати дані набагато швидше, ніж використовуючи поодинокі Put-и. BulkLoad по суті є двокроковою операцією:
- Формування HFile без участі put-ів за допомогою спеціального MapReduce job-и
- Підкладання цих файликів безпосередньо в Hbase
Hbase підтримує виведення своїх метрик до сервера моніторингу Ganglia. Це може бути дуже корисно під час адміністрування Hbase для розуміння суті проблем, що відбуваються з hbase.
RowKey
В якості RowKey використовується ідентифікатор користувача, в якості якого використовується GUUID, рядок, що спеціально генерується таким чином, щоб бути унікальним у всьому світі. GUUID-и розподілені рівномірно, що дає добрий розподіл даних по серверам.
Column Family
У нашому сховищі використовуються дві column family:
- Data. У цій групі колонок зберігаються дані, які втрачають актуальність для рекламних цілей, такі як факти відвідування користувачем певних URL. TTL на цю Column Family встановлено у розмірі 2 місяці, обмеження за кількістю версій — 2000.
- LongData. У цій групі колонок зберігаються дані, які не втрачають своєї актуальності протягом тривалого часу, такі як стать, дата народження та інші «вічні» характеристики користувача.
Колонки
Кожен тип фактів про користувача зберігається в окремій колонці. Наприклад, у колонці Data:_v зберігаються URL, відвідані користувачем, а в колонці LongData:gender — стать користувача.
Як timestamp зберігається час реєстрації цього факту. Наприклад, у колонці Data:_v як timestamp використовується час заходу користувачем певний URL.
Така структура зберігання даних дуже добре лягає на наш патерн використання і дозволяє швидко оновлювати дані про користувачів, швидко діставати всю необхідну інформацію про користувачів, і, використовуючи MapReduce, швидко обробляти дані про всіх користувачів одразу.
7. Альтернативи
HBase досить складна в адмініструванні та використанні, тому перш ніж використовувати HBase є сенс звернути увагу на альтернативи:
Реляційні бази даних. Дуже непогана альтернатива, особливо якщо дані влазять на одну машину. Також насамперед про реляційні бази даних варто подумати у разі, коли важливі транзакції індекси, що відрізняються від первинного.
Key-Value сховища. Такі сховища, як Redis і Aerospike краще підходять, коли необхідна мінімізація latency і менш важлива пакетна обробка даних.
Файли та їх обробка за допомогою MapReduce. Якщо дані лише додаються, і рідко оновлюються/змінюються, краще не використовувати HBase, а просто зберігати дані у файлах. Для спрощення роботи з файлами можна скористатися такими інструментами як Hive, Pig і Impala.
Використання HBase виправдане, коли:
- Даних багато, і вони не влізають на один комп'ютер/сервер
- Данні часто оновлюються та видаляються
- У даних присутній явний «ключ» за яким зручно прив'язувати все інше
- Потрібна пакетна обробка даних
- Потрібен довільний доступ до даних за певним ключем
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ