CubeDB

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 20:14, 1 июня 2018.
CubeDB
Cubelogo.png
Разработчики: Badoo
Написана на: Java
Лицензия: OpenSource
Веб-сайт github.com/cubedb/cubedb/

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 данные сериализуются в читаемом формате.

Технические особенности и ограничения

  1. При запросе данных все процессоры используются параллельно.
  2. Для каждого запроса выполняется полное сканирование записей.
  3. Текущая производительность сканирования составляет около 20 миллионов записей / CPU / second
  4. Для эффективного хранения имен полей используется сжатие словаря. Максимальная мощность поля внутри одного раздела составляет 32677.
  5. Количество полей внутри одного раздела ограничено 256.
  6. Теоретически движок способен вставить 150 000 записей в секунду в худшем случае (без обновлений, только добавления), однако текущее узкое место - это HTTP-интерфейс и время десериализации JSON.
  7. Для визуализации информации разработчики выпустили набор front-end-компонентов для работы с API CubeDB. Этот пакет содержит ряд компонентов React, используя Reat-Bootstrap и D3 для генерации графиков на основе данных CubeDB[2].

Видео по установке CubeDB

Выводы

В ходе выполнения работы была изучена информация о CubeDB, получены навыки установки БД и ее эксплуатирования. Также мною было внесено предложение разработчикам о создании какой-нибудь стартовой страницы для localhost:9998/, так как при первом запуске было непонятно нахолилась ли БД в рабочем состоянии из-за наличия ошибок на данной странице, что, как выяснилось, оказалось нормой.

CubeDB является достаточно простым, но эффективным решением для поставленных перед собой задач. Исходя из того, что было сказано выше, основными достоинствами данной БД можно считать такие характеристики, как:

  1. Производительность. На данный момент CubeDB в Badoo обрабатывает около 12 млрд обращений в день.
  2. Простота.
  3. Хранение информации в особом виде. Позволяет достичь высокой скорости выполнения операций и небольшого объема.

Разработчики не останавливаются на достигнутом и планируют улучшить базу данных следующим образом:

  1. Переписать решение на языке, более пригодном для таких вещей, как быстрая и многопоточная обработка данных.
  2. Научить CubeDB общаться с себе подобными для объединения в целый кластер[3].

Ссылки

Источники

  1. Github[Электронный ресурс]: CubeDB / Дата обращения: 05.05.2018. — Режим доступа: https://github.com/cubedb/cubedb
  2. Github[Электронный ресурс]: React-CubeDB / Дата обращения: 05.05.2018. — Режим доступа: https://github.com/cubedb/react-cubedb
  3. Habr[Электронный ресурс]: CubeDB: минималистичное хранилище счётчиков с многомерными ключами / Дата обращения: 05.05.2018. — Режим доступа: https://habr.com/company/badoo/blog/342564/