Clickhouse Flashcards
Что такое и зачем нужен Clickhouse?
Аналитическая (OLAP) СУБД для витрин. Капризная в настройке и “очень особенная” в использовании, есть своя реализация Х почти для всего на свете (например 30+ реализаций хэш таблицы, из которых выбирает оптимизатор). Но если использовать эти оптимизированные реализации, система будет очень быстрой.
С годами лучше работает с джоинами, но всё равно рекомендуется извне подготавливать широкую денормализованную таблицу (One big table
), и с ней уже работать.
ОЧЕНЬ хорошо справляется с группировками и фильтрациями – основными операциями в BI дашбордах. И хорошо масштабируется горизонтально, т.к. нет единого мастера.
Архитектура Clickhouse
Горизонтально-масштабируемая и отказоустойчивая колоночная СУБД , способная выдерживать большую нагрузку, поддерживать real-time аналитику, и интегрироваться с множеством систем, написанная на C++
Отказоустойчивость достигается за счёт отсутствия мастер-сервера и репликации данных через ReplicatedMergeTree
на другие независимые сервера, в случае падении основного можно мгновенно переключится на соседний, содержащий нужные реплики, т.к. ZooKeeper
автоматически перенаправляет операции, если наш узел падает, а тогда при восстановлении после падения реплика автоматически синхронизируется с остальными докачивая недостающие данные
Реплицировать таблички можно и внутри одного сервера, но тогда не будет отказоустойчивости
Шард в Clickhouse - основный способ горизонтального масштабирования, содержит внутри себя ВСЕ реплики, но данные между шардами уже распределяются, как пример:
Данные разбиты на 2 шарда: Шард 1: пользователи с user_id % 2 = 0. Шард 2: пользователи с user_id % 2 = 1. Каждый шард имеет 3 реплики для надёжности.
В данном примере у нас получилось 6 узлов - 2 шарда, на каждом из которых по половине данных, содержащие 3 реплики, каждая из которых содержит полную копию данных двух других реплик внутри одного шарда. -> 2*3=6
Для координации нескольких реплик, шардов и всех этих узлов используется ZooKeeper
или же Clickhouse Keeper
Также Clickhouse возможно использовать как движок обработки данных поверх S3-хранилища или HDFS-хранилища, для других внешних интеграций Клик поддерживает JDBC
Таким образом - что отказоустойчивость, что горизонтальное масштабирование НЕОБЯЗАТЕЛЬНЫЕ фишки Clickhouse, которые с одной стороны могут позволить достаточно просто его настроить для небольших и не особо важных объёмов данных, но при этом смасштабировать в нужный момент
Clickhouse также умеет реплицировать таблицы через Partition by
, работает полностью аналогично с Greenplum.
Каждая таблица в Clickhouse хранится колоночно, это значит что при обработке мы можем брать только несколько нужных нам колонок и игнорировать чтение остальных, что позволяет поддерживать таблицы с сотнями и даже тысячами столбцов
Засчёт интеграции с стриминговыми сервисами, различными вариантами создания Materialized View
, проекций и других оптимизаций кликхаус способен выдавать real-time/near real-time
аналитику с минимальной задержкой
Центральный элемент в near real-time аналитике - Materialized view
- основная логика которой:
* В нашу таблицу-источник пришли данные либо прошло какое-то время(секунда, минута)
* Это затриггерило перерасчёт в materialized view только по новым данным
* Новые данные агрегаты сложились в нашу целевую таблицу
Это немного упрощённое объяснение, но его будет достаточно
Как шардировать таблички? Что такое шардирование?
Шардирование позволяет распределить фрагменты данных из одной базы по разным узлам кластера, увеличивая пропускную способность и снижая задержку обработки данных.
Шард ClickHouse – это группа копий данных (1+ реплик) для обеспечения отказоустойчивости СУБД. Поскольку шарды содержат разные части данных, для получения всех данных, нужно обращаться ко всем шардам. Запрос на запись или чтение в шард может быть отправлен на любую его реплику.
При этом создается распределенная distributed-таблица, которая маршрутизирует запросы к таблицам по шардам.
Поскольку в Clickhouse, в отличие от Greenplum, нецентрализованная архитектура, SQL-запрос выполняется параллельно, т.е. одновременно на всех сегментах. Например, при вставке с помощью INSERT
-запроса данные сначала записываются в файловую систему хоста, а потом асинхронно копируются с реплики, на которой он выполнен. А вот запрос на выборку с оператором SELECT
отправляет подзапросы на все шарды кластера, независимо от распределения данных. Агрегатные же запросы к шардированным таблицам с оператором GROUP BY
в ClickHouse выполняются так: сперва происходит агрегация на отдельных узлах и эти результаты передаются узлу-инициатору запроса для общей сборки.
Записывать данные в шарды можно двумя способами:
* через distributed-таблицу по ключу шардирования, основанном на хэш-функции конкретного поля, диапазоне значений или вычисляемом динамически, в зависимости от нагрузки;
* Инсёрт напрямую в конкретный шард, чтобы потом считывать данные через distributed-таблицу.
Какие движки использовал? Как работают эти движки?
Движок (engine) это настройка таблицы, которая позволяет оптимизировать работу с таблицей для конкретных сценариев.
Основная группа – MergeTree
, использует сортировку для более быстрой работы с данными.
Для этого необходимо указывать Order By
при создании таблицы, который также автоматически задаёт Primary Key для этой таблицы, если Primary Key не задан отдельно вручную.
Primary Key нужен для реализации гранулярности - т.е. разделения данных на блоки по определённому количеству строк (чаще всего 8192) для ускорения поиска (напоминает индексы)
Merge Tree Называется так из-за особенностей вставки в таблицу, которое производится слиянием диапазонов данных (кусков). Процесс называется OPTIMIZE
, производится в фоне, и командой OPTIMIZE можно MergeTree основаны на LSM-деревьях(Log-Structured Merge)
, и всё что нужно про это знать – что при вставке строки накапливаются в некотором буфере, а потом делается Append куска к остальным. Потом лишнее подчищается.
Для интеграции с Kafka, Postgres, S3 и другими сервисами есть свои движки, например Kafka engine. В них задаются параметры подключения к сервису и конкретному объекту. Похоже на внешние таблицы в Greenplum.
Выше указывал Distributed engine
для работы с распределёнными (шардированными) таблицами.
Для витрин часто подходит AggregatingMergeTree
, который более эффективно группирует данные.
Для словарей есть Dictionary engine
, который оптимизирует джоины с большими таблицами.
> Для merge tree таблиц можно добавить Replicated
, и они начнут реплицироваться согласно конфигу севера. Например ReplicatedAggregatingMergeTree
.
Что происходит при OPTIMIZE:
1. Любой *MergeTree:
* Отсортировать и перезаписать на диск
* Пересобрать индексы и метаданные
* Пометить старые куски удаленными
- Replacing
* Оставить последнюю строку по ключу - Collapsing
* Удалить неактуальные строки - Summing
* Оставить по одной строке, рассчитать строках сумму - Aggregating
* Оставить по одной строке, рассчитать в строках промежуточное значение произвольной функции
Тяжёлые джоины в clickhouse
Для оптимальной производительности стремись сократить количество JOIN
в запросах, особенно для аналитических задач в реальном времени, где требуется производительность в миллисекундах. Стремись к максимум 3-4 соединениям в запросе. Рекомендовано использовать денормализацию, словари и материализованные представления.
В настоящее время ClickHouse не переставляет соединения. Меньшую таблицу располагай справа от JOIN
. Она будет удерживаться в памяти для большинства алгоритмов соединения (hash).
Полезно применять ANY XXX JOIN (н. any left join), который находит только по одному совпадению для каждой пары ключей. А ещё лучше – переписывать JOIN
в подзапросы WHERE IN ()
. Например:
SELECT countIf(VoteTypeId = 2) AS upvotes FROM stackoverflow.votes AS v INNER JOIN stackoverflow.posts AS p ON v.PostId = p.Id WHERE (p.CreationDate >= '2020-01-01')
->
SELECT count() AS upvotes FROM stackoverflow.votes WHERE (VoteTypeId = 2) AND (PostId IN ( SELECT Id FROM stackoverflow.posts WHERE (CreationDate >= '2020-01-01') ))
В Clickhouse и появились разные типы JOIN, и он теперь не так плохо справляется с ними:
* full sorting merge, особенно если таблицы уже отсортированы по ключу
* hash, если правая таблица помещается в память
* grace hash, если допустимы Spill’ы на диск
* и др.
Но всё равно наилучший способ – делать JOIN
во внешней системе перед вставкой в денормализованную таблицу (One big table
).
Мутации в clickhouse
Запросы ALTER TABLE … UPDATE / DELETE, предназначенные для изменения данных таблицы, реализованы с помощью механизма, называемого “мутациями”. В “клике” нет привычных операций Update
, Delete
.
Что важно знать про мутации?
* Не атомарны.
* Выполняются в хронологическом порядке.
* Не блокируют друг друга.
* Не затрагивают строки, вставленные после запуска.
* Продолжат выполняться даже после рестарта.
* Меняют файлы, относящиеся только к указанным столбцам.
Более Clickhouse-native
способ это использовать, например, Replacing движок. Тогда вместо обновления будет вставляться новая версия строки, а старую подчистит OPTIMIZE
. Или можно использовать ключевое слово FINAL
в запросе рядом с каждым FROM и JOIN, чтобы получать последнюю версию строк.
Напоминаю, что кликхауз не гарантирует согласованности, поэтому есть много нюансов :)
Тем не менее, Update
и Delete
всё ещё возможны, просто требуют высокого уровня понимания того, а что ты вообще делаешь, будьте осторожны
TTL(Time to Live)
Настройка строк и/или колонок, которая используется для сдерживания роста объёмов базы.
- Может удалять данные, которые выходят за указанные рамки (старше чем Х дней, больше чем Y GB)
- Охлаждение данных – перенос “архивных” данных в более дешёвое хранилище, например S3. Volume’ы задаются на уровне конфига сервера.
-
Rollup
, когда мы “схлопываем” детальные данные. Например, детализированные факты продаж старше 5 лет объединяем до “продажи за месяц”. В отчётах остаётся агрегированный факт, а строк занимает меньше.
TTL
можно задавать с условием WHERE
Обработка TTL
запускается с процессом OPTIMIZE