ClickHouse — это полигластная база данных, которая может взаимодействовать со множеством внешних систем с помощью специализированных движков или табличных функций. В современных облачных системах важнейшей внешней системой является объектное хранилище. Во-первых, в нем могут храниться «сырые» данные для импорта или экспорта в другие системы (так называемое «озеро данных»). Во-вторых, оно может предложить дешевое и высоконадежное хранилище для табличных данных. Теперь ClickHouse поддерживает оба этих сценария использования S3-совместимого объектного хранилища.
Первые попытки объединить ClickHouse и объектное хранилище были объединены в основную ветку кода более года назад. С тех пор поддержка объектного хранилища значительно эволюционировала. Помимо базового функционала импорта/экспорта, ClickHouse может использовать объектное хранилище для данных таблиц MergeTree. Хотя эта функциональность все еще носит экспериментальный характер, она уже привлекла к себе большое внимание на митапах и вебинарах. В этой статье мы объясним, как работает эта интеграция.
Табличная функция S3
В ClickHouse есть мощный метод интеграции с внешними системами, называемый «табличными функциями». Табличные функции позволяют пользователям экспортировать и импортировать данные из других источников, и таких источников доступно множество, например: сервер MySQL, ODBC- или JDBC-соединение, файл, URL и, с недавних пор, S3-совместимое хранилище. На момент написания статьи табличная функция s3 еще не входит в официальный список, но это должно быть исправлено в ближайшее время. Базовый синтаксис выглядит следующим образом:
s3(path, [aws_access_key_id, aws_secret_access_key,] format, structure, [compression])
Входные параметры
- path | URL бакета. Путь к файлу. В режиме только чтения поддерживает следующие подстановочные знаки: *, ?, {abc,def} и {N..M}, где N, M — числа, а `’abc’, ‘def’` — строки.
- format | Формат данных.
- structure | Структура таблицы. Формат: ‘column1_name column1_type, column2_name column2_type, …’.
- Параметр compression является необязательным, в настоящее время единственным вариантом является ‘gzip’, однако добавляются и другие методы.
Обратите внимание на подстановочные знаки! Они позволяют импортировать несколько файлов за один вызов функции. Например, наш любимый набор данных о поездках нью-йоркских такси, который хранится по одному файлу на месяц, можно импортировать всего одной SQL-командой:
В экземпляре ClickHouse на платформе Altinity.Cloud импорт набора данных с 1,3 млрд строк занимает у меня менее 4 минут!
Несколько важных подсказок:
- Начиная с версии ClickHouse 20.10, пути с подстановочными знаками работают некорректно с «общими» URL-адресами бакетов S3, требуется URL для конкретного региона. Поэтому мы должны использовать: “https://s3.us-east-1.amazonaws.com/altinity-clickhouse-data/” вместо “https://altinity-clickhouse-data.s3.amazonaws.com/”
- С другой стороны, для скачивания одного файла можно использовать удобные URL-адреса бакетов.
- Производительность импорта из S3 сильно зависит от уровня параллелизма на стороне клиента. В режиме glob (по маске) несколько файлов могут обрабатываться параллельно. В приведенном выше примере использовалось 32 потока вставки. Если у вас менее мощный сервер или виртуальная машина, попробуйте задать более высокие значения параметра max_insert_threads. Это можно сделать с помощью команды ‘SET’, например: set max_threads=32, max_insert_threads=32;
set max_threads=32, max_insert_threads=32;
- С другой стороны, параметр ‘input_format_parallel_parsing’ может привести к чрезмерному выделению памяти, поэтому его лучше отключить.
Табличная функция S3 может использоваться не только для импорта, но и для экспорта! Вот как можно выгрузить набор данных ‘ontime’ в S3.
Выгрузка происходит довольно медленно, так как в данном случае мы не можем извлечь выгоду из параллелизма. ClickHouse не может автоматически разделять данные на несколько файлов, поэтому за раз можно выгрузить только один файл. Существует запрос на добавление функции (feature request), которая позволит включить автоматическое партиционирование при вставке во внешнюю табличную функцию. Это сделало бы экспорт более эффективным и удобным.
Также немного раздражает то, что ClickHouse требует указывать структуру таблицы для табличной функции S3. Это также будет улучшено в будущих релизах.
Архитектура хранения ClickHouse
Табличная функция S3 — это удобный инструмент для экспорта или импорта данных, но ее нельзя использовать в реальных рабочих нагрузках вставки и выборки. Требуется более тесная интеграция с системой хранения ClickHouse. Давайте рассмотрим архитектуру хранения ClickHouse более подробно.
Мы уже несколько раз обсуждали хранение ранее в блоге, например в статье «Увеличение емкости ClickHouse с помощью многотомного хранения (Часть 1)». Давайте сделаем краткий обзор. ClickHouse предоставляет несколько уровней абстракции сверху вниз:
- Политики хранения (storage policies) определяют, какие тома могут использоваться и как данные мигрируют с тома на том;
- Тома (volumes) позволяют объединять несколько «дисковых» устройств вместе;
- Диск (disk) представляет собой физическое устройство или точку монтирования.
Когда этот дизайн хранения был реализован в начале 2019 года, ClickHouse поддерживал только один тип диска, который сопоставлялся с точками монтирования ОС. Несколько месяцев спустя команда разработчиков ClickHouse добавила дополнительный уровень абстракции внутри самого диска, который позволяет подключать различные типы дисков. Как можно догадаться, причиной этого была интеграция с объектным хранилищем. Новый тип диска ‘S3’ был добавлен вскоре после этого. Он инкапсулирует особенности взаимодействия с S3-совместимым объектным хранилищем. Теперь мы можем настраивать диски S3 в ClickHouse и хранить все данные или их часть в объектном хранилище.
Конфигурация объектного хранилища
Диски, тома и политики хранения могут быть определены в основном конфигурационном файле ClickHouse config.xml или, что еще лучше, в пользовательском файле внутри папки /etc/clickhouse-server/config.d. Давайте сначала определим диск S3:
config.d/storage.xml:
Это очень базовая конфигурация, ClickHouse поддерживает здесь довольно много различных опций; некоторые из них мы обсудим позже.
После настройки диска S3 его можно использовать в конфигурации томов и политик хранения. Мы можем настроить несколько политик для различных сценариев использования:
- Том S3 в политике рядом с другими томами. Его можно использовать для TTL или ручного перемещения разделов таблицы.
- Том S3 в политике без других томов. Это подход, при котором используется исключительно S3.
А теперь давайте попробуем создать несколько таблиц и переместить данные.
Вставка данных
Для этого примера мы будем использовать набор данных ‘ontime’. Вы можете получить его из руководства ClickHouse (ClickHouse Tutorial) или загрузить из бакета Altinity S3. Таблица содержит 193 млн строк и 109 столбцов, поэтому интересно посмотреть, как она работает с S3, где операции с файлами обходятся дорого. Эталонная таблица называется ‘ontime_ref’ и использует диск EBS по умолчанию. Теперь мы можем использовать ее в качестве шаблона для экспериментов с S3.
Таблица ‘ontime_tiered’ настроена так, чтобы хранить полные 3 года данных на блочном хранилище, а более старые данные перемещать в S3. ‘ontime_s3’ — это таблица, использующая только S3.
Теперь давайте вставим немного данных. В нашей эталонной таблице есть данные по 31 марта 2020 года.
Это произошло практически мгновенно. Данные по-прежнему отправляются на обычный диск. А как насчет таблицы S3?
Такое же количество строк вставляется в 25 раз дольше!
Как только данные попадают в S3, производительность вставки сильно падает. Это, безусловно, нежелательно для многоуровневой таблицы (tiered table), поэтому существует специальная настройка на уровне тома, которая полностью отключает перемещения по TTL во время вставки и запускает их только в фоновом режиме. Вот как ее можно настроить:
При такой настройке вставка всегда попадает на первый диск в политике хранения. Переносы по TTL в соответствующий том выполняются в фоновом режиме. Давайте очистим таблицу «ontime_tiered» и выполним вставку всей таблицы (к слову, truncate занимает много времени).
Это произошло быстро, так как все данные были вставлены на быстрый диск. Мы можем проверить, как данные располагаются на хранилище с помощью этого запроса:
Таким образом, данные уже были перемещены в S3 фоновым процессом. Только 10% данных хранится на локальной файловой системе, а все остальное было перемещено в объектное хранилище. Похоже, это правильный способ работы с дисками S3, поэтому в дальнейшем мы будем использовать «ontime_tiered».
Обратите внимание на колонку «part_type». Таблицы ClickHouse MergeTree могут хранить части данных в различных форматах. Формат «Wide» используется по умолчанию; он оптимизирован для производительности запросов. Однако для него требуется как минимум два файла на колонку. Таблица «ontime» имеет 109 колонок, что приводит к 227 файлам для каждой части. Это главная причина низкой производительности S3 при вставках и удалении.
С другой стороны, «compact» части хранят все данные в одном файле, поэтому вставки в «compact» части происходят намного быстрее (мы это проверили), но производительность запросов снижается. Поэтому ClickHouse использует «compact» части только для небольших частей. Порог по умолчанию составляет 10 МБ (см. настройки дерева слияния «min_bytes_for_wide_part» и «min_rows_for_wide_part»).
Проверка производительности запросов
Чтобы протестировать производительность запросов, мы выполним несколько бенчмарк-запросов для таблиц «ontime_tiered» и «ontime_ref», которые запрашивают исторические данные, поэтому многоуровневая таблица будет использовать хранилище S3. Мы также выполним запрос смешанного диапазона, чтобы подтвердить, что данные S3 и не-S3 могут использоваться вместе, и сравним результаты с эталонной таблицей. Тестирование не будет исчерпывающим, но оно должно дать общее представление о различиях в производительности. Из бенчмарка было выбрано только 4 репрезентативных запроса. Пожалуйста, обратитесь к полному списку в руководстве по ClickHouse.
Этот запрос выполняется за 0.015 с для «ontime_ref» и за 0.318 с для «ontime_tiered». Второй запуск завершается за 0.142 с.
Этот запрос выполняется за 0.063 с для «ontime_ref» и за 0.766/0.518 с для «ontime_tiered».
Этот запрос выполняется за 0.319 с для «ontime_ref» и за 1.016/0.988 с для «ontime_tiered».
Этот запрос выполняется за 0.436 с для «ontime_ref» и за 2.493/2.241 с для «ontime_tiered». На этот раз для многоуровневой таблицы в одном запросе использовались как блочное, так и объектное хранилище.
Итак, производительность запросов с диском S3 определенно снижается, но она все еще достаточно высока для интерактивных запросов. Обратите внимание на прирост производительности при втором запуске. Хотя страничные кэши Linux не могут использоваться для данных S3, ClickHouse локально кэширует индексные файлы и файлы засечек для хранилища S3, что дает заметное ускорение при анализе условий WHERE и выборке данных из S3.
Тестирование на большем наборе данных
Давайте попробуем сравнить производительность запросов на более крупном наборе данных поездок желтого такси Нью-Йорка. Недавно мы использовали его для сравнения с Amazon RedShift. Набор данных содержит 1,3 миллиарда строк. Как отмечалось выше, его можно загрузить из S3 с помощью табличной функции S3. Сначала мы создаем многоуровневую таблицу аналогичным образом:
И вставляем данные:
Это произошло практически мгновенно благодаря производительности хранилища EBS. Теперь давайте посмотрим на размещение данных:
Судя по всему, дата окончания набора данных — 31 декабря 2016 года, поэтому все наши данные отправляются в S3. Вы можете видеть довольно много частей — ClickHouse потребуется некоторое время на их слияние. Если мы проверим тот же запрос через 10 минут, количество частей уменьшится до 3–4 на партицию. Чтобы увидеть не только производительность S3, но и влияние количества частей, мы запускаем бенчмарк-запросы дважды: сначала с 441 частью в таблице S3, а затем с оптимизированной таблицей, которая содержит всего 96 частей после OPTIMIZE FINAL. Обратите внимание, что OPTIMIZE FINAL работает очень медленно на таблице S3, в нашей настройке выполнение заняло около часа.
На диаграмме ниже сравнивается лучший результат из 3 запусков для 5 тестовых запросов:
Как видите, разница в производительности запросов между EBS и S3 MergeTree уже не так существенна по сравнению с небольшим набором данных ontime, и она уменьшается по мере роста сложности запросов. Кроме того, оптимизация таблицы помогает еще больше сократить этот разрыв.
Под капотом
ClickHouse изначально не проектировался для объектного хранилища. Поэтому он активно использует некоторые специфичные для блочного хранилища функции, такие как жесткие ссылки. Как же это работает для хранилища S3? Давайте заглянем в каталог данных ClickHouse, чтобы разобраться.
Для таблиц, не использующих S3, ClickHouse хранит части данных в /var/lib/clickhouse/data/<database>/<table>. Для таблиц S3 вы не найдете данные по этому пути; вместо этого нечто похожее находится в /var/lib/clickhouse/disks/s3/data/<database>/<table>. (Это расположение можно настроить на уровне диска). Однако давайте посмотрим на содержимое:
Это не данные, а ссылка на файл S3. Мы можем найти соответствующий объект S3, заглянув в консоль AWS:
ClickHouse генерирует уникальные файлы для каждого столбца с хэшированными именами и сохраняет ссылки в локальной файловой системе. Слияния, мутации и операции переименования, требующие жестких ссылок в блочном хранилище, реализуются на уровне ссылок, в то время как данные S3 вообще не затрагиваются. Это определенно решает множество проблем, но создает другую: все файлы для всех столбцов всех таблиц хранятся с единым префиксом.
Проблемы и ограничения
Хранилище S3 для таблиц MergeTree все еще находится на стадии экспериментов и имеет некоторые недоработки. Очевидным ограничением является репликация. Предполагается, что объектное хранилище уже реплицируется облачным провайдером, поэтому нет необходимости использовать репликацию ClickHouse и хранить несколько копий данных. ClickHouse должен быть достаточно умным, чтобы не реплицировать таблицы S3. Ситуация становится еще сложнее, когда таблица использует многоуровневое хранение.
Другим недостатком является производительность вставок и слияний. Некоторые оптимизации, такие как параллельные многочастные выгрузки, уже реализованы. Многоуровневые таблицы можно использовать для обеспечения быстрых локальных вставок, но мы не можем изменить законы физики — слияния могут быть довольно медленными. Однако в реальных сценариях использования ClickHouse будет выполнять большинство слияний на быстрых дисках до того, как данные попадут в объектное хранилище. Существует также настройка для полного отключения слияний в объектном хранилище, чтобы защитить исторические данные от ненужных изменений.
Структура данных в объектном хранилище также нуждается в улучшении. В частности, если бы каждая таблица имела отдельный префикс, можно было бы перемещать таблицы между расположениями. Добавление метаданных позволило бы восстановить таблицу из копии в объектном хранилище, если бы все остальное было потеряно.
Еще одна проблема связана с безопасностью. В примерах, приведенных выше, нам приходилось указывать ключи доступа AWS в конфигурации SQL или хранилища ClickHouse. Это определенно неудобно, не говоря уже о безопасности. Есть два варианта, которые облегчают жизнь пользователям. Во-первых, можно передать учетные данные или заголовок авторизации глобально на уровне конфигурации сервера, например:
Во-вторых, поддержка ролей IAM уже находится в разработке. После реализации она делегирует контроль доступа администраторам учетной записи AWS.
Все эти ограничения учитываются в текущей разработке, и мы планируем улучшить реализацию MergeTree S3 в ближайшие несколько месяцев.
Заключение
ClickHouse постоянно адаптируется к потребностям пользователей. Многие функции ClickHouse создаются на основе отзывов сообщества. Поддержка объектного хранилища не является исключением. Эта функция, часто запрашиваемая пользователями сообщества, была в значительной степени реализована разработчиками из команд Yandex.Cloud и Altinity.Cloud. Несмотря на то, что в настоящее время она несовершенна, она уже существенно расширяет возможности ClickHouse. Разработка продолжается; каждая новая функция и улучшение в этой области продвигают ClickHouse на шаг ближе к эффективной работе в облаке. ClickHouse не сбавляет обороты! Следите за новостями.










