CubeDB
Последнее изменение этой страницы: 20:14, 1 июня 2018.
![]() | |
Разработчики: | Badoo |
---|---|
Написана на: | Java |
Лицензия: | OpenSource |
Веб-сайт |
github |
CubeDB - минималистичное хранилище счётчиков с многомерными ключами.
Созданный технической командой Badoo BI CubeDB позволяет отслеживать десятки миллионов входящих событий в реальном времени. База данных хранит все данные в памяти и предназначена для того, чтобы делать только одно: отвечать на простые запросы о количестве точек данных в интервалах раздела очень быстро, т. е. в течение нескольких десятков миллисекунд[1].
Содержание
Структура данных
CubeDB работает с кубами. Куб представляет собой набор точек данных, разделенных на разделы. Каждая точка данных имеет поле разбиения, набор полей размерности строки и набор целочисленных метрических полей. Поле раздела используется для извлечения интервалов разделов, содержащих точки данных.
Пример:
{
"counters": { "c": 139},
"cubeName": "IceCube",
"fields": {
"stamina": 70,
"intellect": 48,
"crit": 31 },
"partition": "2018-05-04"
}
cubeName
- имя куба;partition
- поле разбиения;fields
- набор полей размерности строки;counters
- набор целочисленных метрических полей.
Максимальное количество всевозможных значений для каждого поля небольшое, поэтому оно кодируется цифрой, а именно 16 битами. Такое решение позволяет не только экономить память, но и осуществлять поиск быстрее, так как сравнивать необходимо только 16 бит, а не всю строку. Под счетчики было выделено 64 бита.
Таким образом, ключ screen_name=view_photo,prev_screen=welcome,platform=android,app_version=1.2.3,gender=male
со значением 1500000
имеет вид 1:1:1:1:1 1500000
. И все это занимает 5х2 + 8 = 18 байт.
Также при вставке создается обратный индекс, где ключом будут цифровые значения полей (1:1:1:1:1
), а значением - номер строки, где эта комбинация находится. Такой обратный индекс живет в кэше и создается для каждой партиции. Если к нему не обращались несколько дней, он удаляется и освобождает память.
Сценарии использования
CubeDB позволяет ответить на следующие примерные вопросы:
- подсчитывать количество событий в часовых перегородках;
- подсчитывать количество событий в часовых разделах с заданными значениями параметров;
- подсчитывать количество событий в подинтервале почасовых разделов;
- группировать события в часах по значениям параметров и подсчитывать события в группах;
- группировать события по одному значению, фильтровать по другому и подсчитывать события в группах;
- и так далее.
Результаты представлены в JSON, предназначенном для использования в целях визуализации данных, которые доступны в десятки миллисекунд.
Установка
Необходимый софт: Git, JDK8 и Maven.
git clone git@github.com:sztanko/cubedb.git
или
git clone https://github.com/sztanko/cubedb.git
cd cubedb/
mvn package -DskipTests
mv target/cubedb-*-SNAPSHOT.jar cubedb.jar
java -jar cubedb.jar <port> <path_for_dumps>
//port = 9998
//path="/tmp/cubedumps"
Можно создать .sh
файл для быстрого запуска.
path="/tmp/cubedumps" # Directory for dumps
log_properties="log4j.properties" # Create your own log4.properties
port=9998 # port
jmx_port=5010 # monitoring port
flightRecordsOpts="-XX:+UnlockCommercialFeatures -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.port=$jmx_port"
logOpts="-Dlog4j.configuration=$log_properties"
/usr/java/jdk1.8.0_60/bin/java -XX:MaxDirectMemorySize=10G -Xmx2000M $flightRecordsOpts $logOpts -jar cubedb.jar $port $path
/usr/java/jdk1.8.0_60/bin/java - директория куда установлена java, у Вас может быть другой путь
Также можно создать и запустить Docker контейнер, используя докерфайл из текущей директории.
docker build -t cubedb .
docker run -t -p 80:80 cubedb
API
В настоящее время CubeDB управляется через интерфейс REST. Также CubeDB поддерживает gzip-ованные запросы и ответы.
Статистика
Если все было правильно установлено, то после запуска можно попасть в БД, зайдя на http://localhost:9998/v1/stats
. Здесь можно найти техническую информацию, включая список всех таблиц, количество разделов и т.п. Также там будет указан приблизительный размер, занимаемый данными; количество разделов, которые находятся в куче и вне кучи.
Добавление данных
Данные вставляются при помощи HTTP POST
:
echo $data | curl -s --data-binary "@-" -H "Content-Type: text/json" -X POST http://localhost:9998/v1/insert
Но перед тем как вставить данные, необходимо их записать в JSON. Пример:
read -d '' json <<"EOF"
[
{
"partition": "partition-01",
"counters": {
"c": 1
},
"fields": {
"field_1": "1"
},
"cubeName": "test_cube"
}
]
EOF
echo "$json" | curl -s --data-binary "@-" -H "Content-Type: text/json" -X POST http://localhost:9998/v1/insert
Точки данных вставляются как список карт JSON, каждый из которых представляет собой единую точку данных.
При первом добавлении строки дополняются полями, которые не указаны и не вставлены. Если строка уже существует в БД, счетчики увеличиваются на указанные значения.
Запрос данных
Данные запрашиваются при помощи HTTP GET
:
- Получить данные для всех кубов между разделами
{fromPartition} / {toPartition}
:
curl -s --request GET --header 'Content-Type: application/json' http://localhost:9998/v1/all/from/{fromPartition}/to/{toPartition}
- Получить данные для данного куба
{cubeName}
между разделами{fromPartition} / {toPartition}
:
curl -s --request GET --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}/from/{fromPartition}/to/{toPartition}
- Получить данные для данного куба
{cubeName}
из последних{num}
разделов:
curl -s --request GET --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}/last/{num}
- Получить данные для данного куба
{cubeName}
из последних{num}
разделов, где поле{field_name}
имеет значение{field_value}
:
curl -s --request GET --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}/last/{num}/?{field_name}={field_value}
- Получить данные для данного куба
{cubeName}
из последних{num}
разделов, где данные сгруппированы по полю{field_name}
:
curl -s --request GET --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}/last/{num}/group_by/{field_name}
Удаление данных
Данные удаляются при помощи HTTP DELETE
:
- Удалить данные для всех кубов между разделами
{fromPartition} / {toPartition}
:
curl -s --request DELETE --header 'Content-Type: application/json' http://localhost:9998/v1/all/from/{fromPartition}/to/{toPartition}
- Удалить все, кроме последних
{numPartitions}
разделов:
curl -s --request DELETE --header 'Content-Type: application/json' http://localhost:9998/v1/keep/last/{numPartitions}
- Удалить данные куба
{cubeName}
:
curl -s --request DELETE --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}
- Удалить данные для куба
{cubeName}
между разделами{fromPartition} / {toPartition}
:
curl -s --request DELETE --header 'Content-Type: application/json' http://localhost:9998/v1/{cubeName}/from/{fromPartition}/to/{toPartition}
Сохранение
Необходимо помнить, что данные не сохраняются автоматически при завершении работы. Сохранения должны быть активированы вручную. При запуске данные загружаются из каталога, указанного в аргументе командной строки (<path_for_dumps>
).
Обычное сохранение:
echo $data | curl -s --data-binary "@-" -H "Content-Type: text/json" -X POST http://localhost:9998/v1/save
Сохранение в JSON:
echo $data | curl -s --data-binary "@-" -H "Content-Type: text/json" -X POST http://localhost:9998/v1/saveJSON
- Каждый куб сериализуется в отдельный файл.
- Файлы архивируются gzip.
- Директория, в которой будут храниться дампы, указывается при запуске сервера как аргумент командной строки. В случае с JSON файлы будут храниться в поддиректории основной директории для дампов.
HTTP
ответ от данного запроса вернет адрес директории с дампами.- Данные сериализуются во внутреннем, высокоэффективном двоичном формате. В случае с JSON данные сериализуются в читаемом формате.
Технические особенности и ограничения
- При запросе данных все процессоры используются параллельно.
- Для каждого запроса выполняется полное сканирование записей.
- Текущая производительность сканирования составляет около 20 миллионов записей / CPU / second
- Для эффективного хранения имен полей используется сжатие словаря. Максимальная мощность поля внутри одного раздела составляет 32677.
- Количество полей внутри одного раздела ограничено 256.
- Теоретически движок способен вставить 150 000 записей в секунду в худшем случае (без обновлений, только добавления), однако текущее узкое место - это HTTP-интерфейс и время десериализации JSON.
- Для визуализации информации разработчики выпустили набор front-end-компонентов для работы с API CubeDB. Этот пакет содержит ряд компонентов React, используя Reat-Bootstrap и D3 для генерации графиков на основе данных CubeDB[2].
Видео по установке CubeDB
Выводы
В ходе выполнения работы была изучена информация о CubeDB, получены навыки установки БД и ее эксплуатирования. Также мною было внесено предложение разработчикам
о создании какой-нибудь стартовой страницы для localhost:9998/
, так как при первом запуске было непонятно нахолилась ли БД в рабочем состоянии из-за наличия
ошибок на данной странице, что, как выяснилось, оказалось нормой.
CubeDB является достаточно простым, но эффективным решением для поставленных перед собой задач. Исходя из того, что было сказано выше, основными достоинствами данной БД можно считать такие характеристики, как:
- Производительность. На данный момент CubeDB в Badoo обрабатывает около 12 млрд обращений в день.
- Простота.
- Хранение информации в особом виде. Позволяет достичь высокой скорости выполнения операций и небольшого объема.
Разработчики не останавливаются на достигнутом и планируют улучшить базу данных следующим образом:
- Переписать решение на языке, более пригодном для таких вещей, как быстрая и многопоточная обработка данных.
- Научить CubeDB общаться с себе подобными для объединения в целый кластер[3].
Ссылки
Источники
- ↑ Github[Электронный ресурс]: CubeDB / Дата обращения: 05.05.2018. — Режим доступа: https://github.com/cubedb/cubedb
- ↑ Github[Электронный ресурс]: React-CubeDB / Дата обращения: 05.05.2018. — Режим доступа: https://github.com/cubedb/react-cubedb
- ↑ Habr[Электронный ресурс]: CubeDB: минималистичное хранилище счётчиков с многомерными ключами / Дата обращения: 05.05.2018. — Режим доступа: https://habr.com/company/badoo/blog/342564/
ISSN 2542-0356
Следуй за Полисом
Оставайся в курсе последних событий
Лицензия
Если не указано иное, содержание этой страницы доступно по лицензии Creative Commons «Attribution-NonCommercial-NoDerivatives» 4.0, а примеры кода – по лицензии Apache 2.0. Подробнее см. Условия использования.