Сегодня разберем, как из ClickHouse обратиться к встроенной key-value БД RockDB, используя табличный движок EmbeddedRocksDB, и познакомимся с возможностями новой песочницы колоночной базы данных.
Постановка задачи и DDL-скрипты
Колоночная СУБД ClickHouse поддерживает несколько движков таблиц, включая интеграционные механизмы для взаимодействия со сторонними системами, одной из которых является key-value база данных RocksDB. В качестве примера рассмотрим работу с данными пользовательского поведения, когда пользователю выдается временный ключ, например, для входа в систему (как в интернет-банке):
- для хранения ключей, выданных пользователям будем использовать таблицу sessions_keys с движком EmbeddedRocksDB и временем жизни значения 5 секунд;
- данные о пользовательском аккаунте будут храниться в таблице user_accounts;
Сперва создадим таблицу session_keys с тремя столбцами: key, value и start_time, задав у столбца value время жизни (TTL, Time To Live) в 5 секунд, чтобы удалять записи через 5 секунд после их вставки. В качестве первичного ключа PRIMARY KEY используется столбец key.
CREATE TABLE IF NOT EXISTS session_keys ( key UInt32, value String TTL INTERVAL 5 SECOND, start_time DateTime ) ENGINE = EmbeddedRocksDB PRIMARY KEY key;
Затем вставим данные в эту таблицу, сгенерировав 10 записей с помощью функции numbers_mt(10), где каждая запись имеет случайный ключ key в диапазоне от 0 до 99, случайное строковое значение value и время старта start_time, равное текущему времени с добавлением случайного числа секунд в пределах текущего дня:
INSERT INTO session_keys SELECT toUInt32(rand() % 100) as key, toString(rand()) as value, toDateTime(now()) + (rand() % (60*60*24)) as start_time FROM numbers_mt(10);
Создадим таблицу user_accounts с двумя столбцами: u_id и login, используя движок Log, который оптимизирован для последовательной вставки данных.
CREATE TABLE IF NOT EXISTS user_accounts ( u_id UInt32, login String ) ENGINE = Log;
В таблицу session_keys вставим 10 записей с помощью функции numbers_mt(10), где каждая запись имеет случайный key в диапазоне от 0 до 99, случайное строковое value и start_time, равное текущему времени с добавлением случайного числа секунд, чтобы получить различное время начала в пределах одного дня.
INSERT INTO session_keys SELECT toUInt32(rand() % 100) as key, toString(rand()) as value, toDateTime(now()) + (rand() % (60*60*24)) as start_time FROM numbers_mt(10);
В таблицу user_accounts вставим 10 записей с уникальными идентификаторами u_id и случайно сгенерированными логинами login в формате электронной почты:
INSERT INTO user_accounts SELECT toUInt32(rand() % 100) as u_id, concat(randomPrintableASCII(2), '@', randomPrintableASCII(2), '.com') as login FROM numbers_mt(10);
Поскольку Clickhouse не очень хорошо работает с соединениями таблиц, желательно их ускорить. Для этого установим прямое соединение с таблицами EmbeddedRocksDB, которое позволяет избежать формирования хеш-таблицы в памяти и обеспечивает доступ к данным непосредственно из этой встроенной БД. Это особенно экономит память при больших соединениях, поскольку хеш-таблица не создается. Для включения прямого соединения используем инструкцию:
SET join_algorithm = 'direct';
Чтобы показать упорядоченные по времени выдачи ключа и соединенные по идентификатору пользователя данные из таблиц session_keys и user_accounts, зададим следующий SQL-запрос:
SELECT 'Ключи по пользователям (результаты соединения)'; SELECT session_keys.value, user_accounts.login, session_keys.start_time FROM user_accounts JOIN session_keys ON session_keys.key = user_accounts.u_id ORDER BY start_time DESC;
Далее протестируем все эти запросы в онлайн-песочнице Clickhouse.
Пример реализации в онлайн-песочнице Clickhouse
Для реализации ранее представленных запросов буду использовать онлайн-песочницу ClickHouse, которая позволяет выполнять SQL-запросы из браузера без наличия экземпляра базы данных на стороне пользователя. В отличие от предыдущей песочницы, о которой я писала здесь, в сервисе Fiddle можно выполнять несколько SQL-запросов, включая DDL, в произвольной версии ClickHouse и делиться результатами их выполнения через сгенерированную ссылку. Благодаря поддержке DDL-запросов можно создать таблицу, вставить несколько строк и выполнить к ним запрос. Вообще по сравнению с прошлой песочницей, набор пользовательских прав, т.е. привилегий гораздо шире, полный перечень которых можно посмотреть с помощью команды
SHOW PRIVILEGES
Данные одного выполнения недоступны при другом запуске, поскольку изоляция достигается посредством контейнеризации. Выполнение простого запроса к горячей версии базы данных , которая недавно уже использовалась для другого запроса, занимает несколько секунд.
Точкой входа для пользователей является простое веб-приложение, доступное по адресу fiddle.clickhouse.com. Пользователи взаимодействуют с платформой с помощью HTTP API. Все запросы передаются главному компоненту системы — ядру песочницы. Для каждого запроса пользователя создается Docker-контейнер с нужной версией ClickHouse. Сервис распределяет входящую нагрузку по доступным машинам и запускает на них Docker-контейнеры. Чтобы оптимизировать задержку выполнения запроса, сервис проверяет активность исполнителей и собирает с них информацию о нагрузке, чтобы учитывать это при балансировке.
При запуске своего запроса в онлайн-песочнице Clickhouse Происходит следующий набор действий:
- ядро сервиса выбирает доступную машину, используя алгоритм балансировки нагрузки;
- если на выбранной машине нет Docker-образа с нужной версией ClickHouse, он извлекается из реестра;
- создается и запускается Docker- контейнер;
- в этом контейнере запускаются SQL-запросы;
- по результатам выполнения запросов контейнер прекращает свое существование, а пользователь получает результирующие данные.
Можно сохранить результаты выполнения запросов, чтобы делиться ими по ссылке. Эфемерные контейнеры помогают изолировать запуски друг от друга с помощью механизма cgroups. По сравнению с постоянно включенными экземплярами базы данных этот подход работает чуть медленнее из-за задержки при извлечении образа и создании контейнеров, зато для запуска всей платформы требуется значительно меньше ресурсов. При этом координатор контейнеров работает быстрее, чем системы оркестровки, благодаря простоте и меньшей требовательности к вычислительным ресурсам.
В этой песочнице я запустила вышеприведенные запросы, дополнив их строковым выводом для наглядности:
CREATE TABLE IF NOT EXISTS session_keys ( key UInt32, value String TTL INTERVAL 5 SECOND, start_time DateTime ) ENGINE = EmbeddedRocksDB PRIMARY KEY key; INSERT INTO session_keys SELECT toUInt32(rand() % 100) as key, toString(rand()) as value, toDateTime(now()) + (rand() % (60*60*24)) as start_time FROM numbers_mt(10); SELECT 'Выданные ключи (session_keys)'; SELECT * FROM session_keys LIMIT 5; CREATE TABLE IF NOT EXISTS user_accounts ( u_id UInt32, login String ) ENGINE = Log; INSERT INTO user_accounts SELECT toUInt32(rand() % 100) as u_id, -- Используем number чтобы гарантировать повторение u_id concat(randomPrintableASCII(2), '@', randomPrintableASCII(2), '.com') as login FROM numbers_mt(10); SELECT ''; SELECT 'Логины пользователей (user_accounts)'; SELECT * FROM user_accounts LIMIT 5; SET join_algorithm = 'direct'; SELECT ''; SELECT 'Ключи по пользователям (результаты соединения)'; SELECT session_keys.value, user_accounts.login, session_keys.start_time FROM user_accounts JOIN session_keys ON session_keys.key = user_accounts.u_id ORDER BY start_time DESC;
В следующий раз продолжим знакомиться с возможностями ClickHouse и разберем интеграцию с Apache Kafka и сервисом BI-аналитика от Яндекса.
Освойте администрирование и эксплуатацию ClickHouse для аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники