Пошагово: как ClickHouse распараллеливает агрегационный запрос
Распределение работы между линиями обработки
n параллельными линиями обработки, которые передают и обрабатывают данные блок за блоком, формируя итоговый результат:
Количество
n параллельных линий обработки задаётся настройкой max_threads, которая по умолчанию соответствует числу ядер (потоков) одного CPU, доступных ClickHouse на сервере. В примере выше мы предполагаем 4 ядра.
На машине с 8 ядрами пропускная способность выполнения запроса примерно удвоилась бы (но использование памяти также соответственно увеличилось бы), поскольку больше линий обработки обрабатывают данные параллельно:
Эффективное распределение данных по линиям обработки — ключевой фактор для максимального использования CPU и сокращения общего времени выполнения запроса.
Обработка запросов к таблицам, разбитым на сегменты
Сервер, который первым получает запрос, собирает все промежуточные результаты с сегментов и объединяет их в итоговый глобальный результат. Распределение нагрузки запросов по сегментам позволяет горизонтально масштабировать параллелизм, особенно в средах с высокой пропускной способностью.
ClickHouse Cloud использует параллельные реплики вместо сегментовВ ClickHouse Cloud такой же уровень параллелизма достигается с помощью параллельных реплик, которые работают аналогично сегментам в кластерах с архитектурой shared-nothing. Каждая реплика ClickHouse Cloud — не имеющий состояния вычислительный узел — параллельно обрабатывает часть данных и вносит свой вклад в итоговый результат, подобно независимому сегменту.
Мониторинг параллелизма запросов
- ① ClickHouse должен прочитать 3 609 гранул (обозначенных как marks в трассировочных логах) в 3 диапазонах данных.
- ② При наличии 59 ядер CPU он распределяет эту работу между 59 параллельными потоками обработки — по одному на каждую линию.
× 59 выполняются параллельно в непересекающихся областях данных по 59 параллельным линиям обработки. Это соответствует значению max_threads и показывает, как каждый этап запроса распараллеливается по ядрам CPU.
Встроенный веб-интерфейс ClickHouse (доступный по конечной точке /play) может отображать приведённый выше физический план в виде графической визуализации. В этом примере мы устанавливаем max_threads в 4, чтобы визуализация оставалась компактной и показывала только 4 параллельные линии обработки:
Примечание: Читайте визуализацию слева направо. Каждая строка соответствует параллельной линии обработки, которая передаёт данные блок за блоком, применяя такие преобразования, как фильтрация, агрегация и финальные этапы обработки. В этом примере показаны четыре параллельные линии, соответствующие настройке max_threads = 4.
Балансировка нагрузки между линиями обработки
Resize в приведённом выше физическом плане переразбивают и перераспределяют потоки блоков данных между линиями обработки, чтобы равномерно распределять нагрузку между ними. Такое перераспределение особенно важно, когда диапазоны данных различаются по числу строк, соответствующих предикатам запроса; иначе одни линии могут оказаться перегруженными, а другие — бездействовать. Благодаря такому перераспределению более быстрые линии фактически помогают более медленным, что оптимизирует общее время выполнения запроса.
Почему max_threads не всегда применяется
n параллельных линий обработки задаётся настройкой max_threads, которая по умолчанию соответствует количеству ядер CPU, доступных ClickHouse на сервере:
max_threads может не учитываться в зависимости от объёма данных, выбранных для обработки:
max_threads задано значение 59, ClickHouse использует для чтения данных только 30 параллельных потоков.
Теперь выполним запрос:
max_threads, ClickHouse выделяет дополнительные параллельные линии обработки только тогда, когда для этого достаточно данных. «max» в max_threads означает верхний предел, а не гарантированное число используемых потоков.
То, что считается «достаточным объёмом данных», в первую очередь определяется двумя настройками: они задают минимальное число строк (по умолчанию 163,840) и минимальное число байтов (по умолчанию 2,097,152), которые должна обрабатывать каждая линия обработки:
Для кластеров shared-nothing:
Для кластеров с общим хранилищем (например, ClickHouse Cloud):
- merge_tree_min_rows_for_concurrent_read_for_remote_filesystem
- merge_tree_min_bytes_for_concurrent_read_for_remote_filesystem
max_threads.
Это показывает, что для запросов к небольшим наборам данных ClickHouse намеренно ограничивает параллелизм. Используйте переопределения настроек только для тестирования, а не в продакшене, так как это может привести к неэффективному выполнению запросов или конкуренции за ресурсы.
Ключевые выводы
- ClickHouse распараллеливает запросы, используя линии обработки, число которых связано с
max_threads. - Фактическое число линий зависит от объема данных, выбранных для обработки.
- Используйте
EXPLAIN PIPELINEи трассировочные логи, чтобы анализировать, как используются линии обработки.
Где найти дополнительную информацию
- Слой обработки запросов — статья VLDB 2024 (веб-версия) - Подробный разбор внутренней модели выполнения ClickHouse, включая планирование, конвейерную обработку и архитектуру операторов.
- Объяснение промежуточных состояний агрегации - Технический разбор того, как промежуточные состояния агрегации обеспечивают эффективное параллельное выполнение по линиям обработки.
- Видеоруководство с подробным разбором всех этапов обработки запросов в ClickHouse: