Введение
В этом руководстве мы сначала рассмотрим, как ClickHouse распределяет запрос по нескольким сегментам с помощью distributed таблиц, а затем — как запрос может задействовать несколько реплик при выполнении.В архитектуре shared-nothing кластер обычно разделяется на несколько сегментов, при этом каждый сегмент содержит подмножество всех данных. Над этими сегментами располагается distributed таблица, предоставляющая единое представление всего набора данных. Операции чтения можно направлять в локальную таблицу. В этом случае выполнение запроса будет происходить только на указанном сегменте. Либо запрос можно направить в distributed таблицу, и тогда каждый сегмент выполнит данный запрос. Сервер, на котором был выполнен запрос к distributed таблице, агрегирует данные и вернет ответ клиенту: На рисунке выше показано, что происходит, когда клиент выполняет запрос к distributed таблице:
- Запрос SELECT отправляется в distributed таблицу на одном из узлов произвольным образом (по стратегии round-robin или после маршрутизации на конкретный сервер с помощью балансировщика нагрузки). Этот узел начинает выступать в роли координатора.
- Узел определяет каждый сегмент, который должен выполнить запрос, на основе информации, указанной в distributed таблице, после чего запрос отправляется в каждый сегмент.
- Каждый сегмент читает, фильтрует и агрегирует данные локально, а затем отправляет координатору состояние, пригодное для слияния.
- Координирующий узел объединяет данные, а затем отправляет ответ клиенту.
Архитектура без сегментирования
Введение в параллельные реплики
- Запрос от клиента проходит через балансировщик нагрузки и отправляется на один из узлов. Этот узел становится координатором для данного запроса.
- Узел анализирует индекс каждой части и выбирает подходящие части и гранулы для обработки.
- Координатор разбивает рабочую нагрузку на набор гранул, которые могут быть назначены разным репликам.
- Каждый набор гранул обрабатывается соответствующими репликами, а по завершении на координатор отправляется состояние, пригодное для слияния.
- Наконец, координатор объединяет все результаты от реплик и возвращает ответ клиенту.
- Некоторые реплики могут быть недоступны.
- Репликация в ClickHouse асинхронна, поэтому в определенный момент времени у реплик могут быть разные части.
- Нужно как-то учитывать высокую задержку на отдельных репликах.
- Файловый кэш различается от реплики к реплике в зависимости от активности на каждой из них, поэтому случайное назначение задач может привести к менее оптимальной производительности из-за локальности кэша.
Уведомления
- Запрос от клиента проходит через балансировщик нагрузки и отправляется на один из узлов. Этот узел становится координатором данного запроса.
- Узел-координатор отправляет запрос на получение уведомлений от всех реплик в кластере. У реплик могут быть немного разные представления о текущем наборе частей таблицы. Поэтому эту информацию нужно собрать, чтобы избежать неверных решений при планировании.
- Затем узел-координатор использует уведомления, чтобы определить набор гранул, которые можно назначить разным репликам. Здесь, например, видно, что реплике 2 не была назначена ни одна гранула из части 3, потому что эта реплика не включила эту часть в свое уведомление. Также обратите внимание, что реплике 3 не было назначено ни одной задачи, потому что от этой реплики не поступило уведомление.
- После того как каждая реплика обработала запрос на своем подмножестве гранул и объединяемое состояние было отправлено обратно координатору, координатор объединяет результаты, и ответ отправляется клиенту.
Динамическая координация
- Реплики сообщают узлу-координатору, что готовы обрабатывать задачи; они также могут указать, какой объём работы способны взять.
- Координатор назначает репликам задачи.
- Реплики 1 и 2 завершают свою задачу очень быстро. Они запрашивают у узла-координатора ещё одну задачу.
- Координатор назначает новые задачи репликам 1 и 2.
- Все реплики уже завершили обработку своих задач. Они запрашивают дополнительные задачи.
- Координатор, используя уведомления, проверяет, какие задачи ещё осталось обработать, но таких задач больше нет.
- Координатор сообщает репликам, что всё обработано. Теперь он объединит все состояния, подлежащие слиянию, и вернёт ответ на запрос.
Управление локальностью кэша
| Реплика 1 | Реплика 2 | Реплика 3 | |
|---|---|---|---|
| Часть 1 | g1, g6, g7 | g2, g4, g5 | g3 |
| Часть 2 | g1 | g2, g4, g5 | g3 |
| Часть 3 | g1, g6 | g2, g4, g5 | g3 |
max_parallel_replicas меньше
числа реплик, то для выполнения запроса случайным образом выбираются реплики.
Перехват задач
Ограничения
Если вы столкнулись с проблемой, которая не относится ни к одному из перечисленных ниже ограничений, и
подозреваете, что её причина — параллельная реплика, пожалуйста, создайте issue в GitHub, используя
метку
comp-parallel-replicas.| Ограничение | Описание |
|---|---|
| Сложные запросы | В настоящее время параллельная реплика достаточно хорошо работает с простыми запросами. Дополнительные уровни сложности, такие как CTE, подзапросы, JOIN, неплоские запросы и т. д., могут негативно сказываться на производительности запроса. |
| Небольшие запросы | Если вы выполняете запрос, который обрабатывает небольшое количество строк, запуск на нескольких репликах может не дать прироста производительности, поскольку сетевые затраты на координацию между репликами могут приводить к дополнительным накладным расходам при выполнении запроса. Вы можете уменьшить влияние этой проблемы, используя настройку parallel_replicas_min_number_of_rows_per_replica. |
| Параллельные реплики отключаются при использовании FINAL | |
| Проекции не используются вместе с параллельными репликами | |
| Данные с высокой мощностью и сложная агрегация | Агрегация по данным с высокой мощностью, при которой требуется передавать большие объёмы данных, может значительно замедлить выполнение запросов. |
| Совместимость с новым анализатором | Новый анализатор в некоторых сценариях может как значительно замедлить, так и ускорить выполнение запроса. |
| Настройка | Описание |
|---|---|
enable_parallel_replicas | 0: отключено1: включено 2: Принудительно использовать параллельные реплики; если они не будут задействованы, будет сгенерировано исключение. |
cluster_for_parallel_replicas | Имя кластера, используемого для параллельной репликации; если вы используете ClickHouse Cloud, укажите default. |
max_parallel_replicas | Максимальное количество реплик, используемых для выполнения запроса на нескольких репликах; если указано число меньше количества реплик в кластере, узлы будут выбраны случайным образом. Это значение также может быть завышено с учетом горизонтального масштабирования. |
parallel_replicas_min_number_of_rows_per_replica | Помогает ограничить количество используемых реплик в зависимости от числа строк, которые необходимо обработать; количество используемых реплик определяется так: estimated rows to read / min_number_of_rows_per_replica. |
enable_analyzer | Выполнение запросов с параллельными репликами поддерживается только при включенном анализаторе |
Исследование проблем с параллельными репликами
system.query_log. Также
можно посмотреть таблицу system.events,
чтобы увидеть все события, произошедшие на сервере, а также использовать
табличную функцию clusterAllReplicas, чтобы увидеть таблицы на всех репликах
(если вы используете Cloud, укажите default).
Query
Ответ
Ответ
Response
system.text_log также
содержит информацию о выполнении запросов при использовании параллельных реплик:
Query
Ответ
Ответ
Response
EXPLAIN PIPELINE. Он показывает, как ClickHouse
будет выполнять запрос и какие ресурсы будут задействованы при его
выполнении. Возьмем, к примеру, следующий запрос:
EXPLAIN PIPELINE (without parallel replica)
EXPLAIN PIPELINE (with parallel replica)