Репликация создаёт копии одного набора данных для доступности и чтения. Шардирование распределяет разные части набора между узлами для хранения и вычислений. Их часто используют вместе.
Два шарда по две реплики
Представим четыре узла. Узлы 1 и 2 содержат один набор фактов первого шарда. Узлы 3 и 4 — другой набор второго шарда. Обычный запрос через Distributed выбирает одну доступную реплику каждого шарда и объединяет результаты. Читать все четыре как независимые наборы нельзя: данные удвоятся.
Реплики помогают пережить отказ узла и распределить чтение. Шарды помогают распределить объём и вычисления. При этом сеть, неравномерность данных и финальная агрегация у инициатора могут ограничивать ускорение.
ReplicatedMergeTree и Keeper
ReplicatedMergeTree координирует записи и слияния через ClickHouse Keeper либо совместимый ZooKeeper. Keeper хранит координационные метаданные: состояние реплик, журнал действий, сведения о частях. Сами аналитические строки передаются между ClickHouse-узлами и хранятся в их таблицах.
Репликация данных действует на уровне таблицы. ON CLUSTER распространяет команду по настроенному кластеру, а Replicated database engine управляет распространением DDL. Пользователей и остальные настройки обслуживают отдельно.
Узлы могут принимать записи, а остальные реплики догоняют асинхронно. После успешного INSERT другая реплика способна временно вернуть старые данные. Quorum-настройки позволяют потребовать запись на нескольких репликах, но увеличивают требования к доступности и задержку. Даже после таймаута клиент должен учитывать возможность уже принятой записи.
Дедупликация повторных блоков использует ограниченный журнал. Это не бессрочная уникальность бизнес-ключа и не защита от двух по-разному сформированных событий с одним ID.
Distributed — маршрутизация
Локальные таблицы на шардах хранят parts. Distributed знает конфигурацию кластера и направляет к ним чтение и запись. Для вставок ключ шардирования определяет узел назначения.
Стабильный хеш event_id может равномерно распределять события. Ключ категории локализует часть запросов, но популярная категория способна перегрузить шард. Поэтому вместе с кардинальностью — числом различных значений — проверяют частоты и объём данных для каждого значения.
При фоновой отправке INSERT Distributed может подтвердить сохранение файлов очереди на инициаторе. Foreground-режим и настройки сохранности меняют границу ожидания. Требуемое подтверждение записи на шарды определяют для конкретного маршрута.
Для реплицированных локальных таблиц обычно настраивают internal_replication: Distributed отправляет данные одной реплике шарда, а table engine распространяет их дальше. Если бездумно отправлять одинаковые данные всем репликам, можно получить повторы или зависимость от окна дедупликации.
Добавление шарда меняет маршрутизацию будущих вставок при соответствующей настройке. Старые parts не переезжают автоматически. Изменение ключа требует отдельного плана перераспределения и проверки совместного чтения старых и новых данных.
Как объединяется запрос
Шарды читают данные и строят частичные результаты. Инициатор, или координатор запроса, — узел, который принял запрос и организует распределённое выполнение. Он объединяет состояния агрегатов и завершает необходимые стадии сортировки или LIMIT. Среднее должно объединять сумму и количество, а не усреднять готовые средние шардов. Инициатором может быть обычный ClickHouse-узел; Keeper не выполняет эту аналитическую работу.
Перекос данных
Data skew, или перекос, — неравномерность данных и работы между участниками параллельного вычисления. Важны число строк, размер значений и частота ключей. Даже при одинаковом объёме таблиц фильтр одного запроса может выбрать почти всё на одном шарде. Остальные завершат свою часть раньше, а общее время будет зависеть от перегруженного узла.
Хеш не разделяет строки с одним и тем же ключом между разными шардами. Частый ключ либо единое значение, которым заменили отсутствующие ключи, может сосредоточить много данных на одном узле. Проверяют распределение строк и байтов, популярные значения и время выполнения на каждом шарде. Смена ключа, отдельная обработка частых значений или предварительная агрегация помогают лишь тогда, когда сохраняют требуемый результат и расположение данных для JOIN.
Как обсуждать CAP
CAP описывает конфликт согласованности и доступности при сетевом разделении. C — согласованное представление операций, обычно линейризуемость; A — ответ на операцию от любого исправного узла; P — возможность разделения сети. Для системы, продолжающей работу при таком разделении, согласованность и доступность могут конфликтовать.
У ClickHouse нужно назвать конкретный путь и настройку. При асинхронной репликации чтение отставшей копии может вернуть старое состояние. Quorum-запись требует достаточного числа реплик и способна отказать, когда они недоступны; сама по себе она не обещает линейризуемость любого чтения. Координация через Keeper имеет собственный кворум и ограничения доступности, отличные от чтения локальных частей.
Гарантии ClickHouse описывают для конкретной операции: кто подтверждает запись, какую реплику читает запрос и что происходит при потере связи.