Logo

Сотни Ядер и ClickHouse: Как 10 Инженерных Решений Intel Достигли Линейной Масштабируемости

Отчет Intel от 17.09.2025: оптимизация ClickHouse для сотен ядер. Устранение блокировок ускорило запросы на 89%, переписывание AST — в 11.5 раз, а параллелизм слияний дал прирост в 264%.

14 жовтня 2025 р., 12:44
6 мин чтения

ClickHouse: Глубокая оптимизация для высокоядерных процессоров Intel

С ростом количества ядер в процессорах до беспрецедентных значений, таких как 128 P-ядер на сокет в Intel Granite Rapids или 288 E-ядер в Sierra Forest, оптимизация программного обеспечения становится исключительно важной. В системах с сотнями ядер на сокет, например в двухсокетных конфигурациях, их число может превышать 400. В отчёте, опубликованном ClickHouse 17 сентября 2025 года и подготовленном инженерами Intel Shanghai, представлены детальные результаты работы по адаптации колонковой СУБД (СУБД) ClickHouse к этим новым условиям.

Исследование Intel выявило пять ключевых направлений, требующих серьёзной переработки для эффективного задействования возможностей высокоядерных процессоров: уменьшение конфликтов блокировок, оптимизация работы с памятью, повышение уровня параллелизма задач, внедрение современных алгоритмических приёмов, включая SIMD-инструкции, и борьбу с «ложным разделением» (false sharing) кэша. Как отмечают авторы, без этих мер рост количества ядер может не только не принести ожидаемого эффекта, но и создать новые узкие места.

Устранение конфликтов блокировок

Конфликты блокировок - одно из самых серьёзных препятствий масштабируемости в многоядерных системах. Согласно закону Амдала, даже небольшая доля последовательного кода способна сильно ограничить общее ускорение. Инженеры Intel продемонстрировали, что если N потоков конкурируют за одну и ту же блокировку, время ожидания растёт квадратично по отношению к N.

  1. Оптимизация кэша условий запросов (QueryConditionCache). Изначально кэш условий запросов в ClickHouse, сохраняющий результаты фильтров WHERE, использовал эксклюзивные блокировки для всех операций, хотя большинство из них были чтениями. На системе с 2×240 виртуальными ЦПУ функция native_queued_spin_lock_slowpath поглощала до 76 % процессорного времени. Решение заключалось во внедрении double-checked locking с атомарными операциями и применении разделяемых блокировок для чтения (быстрый путь) и эксклюзивных - для записи (медленный путь), что снизило нагрузку функции до 1 %. Это улучшило производительность запросов Q10 и Q11 из ClickBench на 85 % и 89 % соответственно, а общее геометрическое среднее по всем запросам ClickBench возросло на 8.1 %. Изменения вошли в PR #80247.

  2. Потоково-локальные идентификаторы таймеров (Thread-Local Timer ID). Профайлер запросов ClickHouse, часто создающий и удаляющий глобальную переменную timer_id, также генерировал значительные конфликты блокировок. Перевод timer_id в потоково-локальное состояние (thread_local) позволил избавиться от глобальных блокировок при включении/выключении таймеров, устранив узкие места профилирования и повысив масштабируемость на системах с высокой плотностью ядер. Эта оптимизация реализована в PR #48778.

Эффективное управление памятью

Менеджмент памяти в высокоядерных системах заметно отличается от однопоточных сценариев. Проблемы включают конкуренцию за аллокаторы, снижение пропускной способности памяти на ядро и каскадные падения производительности из-за неэффективных паттернов выделения.

  1. Оптимизация повторного использования памяти Jemalloc. В ClickHouse агрегации работают с двухуровневыми хеш-таблицами, которые после завершения запроса освобождаются. Однако стандартные настройки jemalloc усложняли повторное использование крупных блоков для последующих мелких аллокаций. Увеличив параметр lg_extent_max_active_fit с 6 (64×) до 8 (256×) в конфигурации jemalloc, удалось значительно повысить эффективность повторного использования памяти. В результате запрос Q35 из ClickBench ускорился на 96.1 % и потребление памяти (VmRSS) сократилось на 45.4 %. Эта модификация доступна через PR #80245.

  2. Переписывание запросов AST для снижения потребления памяти. Запрос Q29 из ClickBench, содержащий множество выражений вида SUM(ResolutionWidth + literal), порождал до 90 временных столбцов. Оптимизатор ClickHouse был доработан, чтобы трансформировать sum(column + literal) в sum(column) + count(column) * literal, что сократило объём временных данных. Эта оптимизация ускорила запрос Q29 в 11.5 раза на системе с 2×80 виртуальными ЦПУ и подняла геометрическое среднее по всем запросам ClickBench на 5.3 %. Подробности - в PR #57853.

Увеличение параллелизма

Этап слияния агрегаций в ClickHouse часто становился боттлнеком при росте числа потоков, если он не был достаточно распараллелен.

  1. Параллельная конвертация хеш-таблиц. Запрос Q5 из ClickBench проявлял заметное падение производительности при росте ядер с 80 до 112 из-за последовательной обработки при конвертации хеш-таблиц. Инженеры Intel распараллелили процесс трансформации одноуровневых хеш-таблиц в двухуровневые. Это дало ускорение запроса Q5 на 264 % на системе с 2×112 виртуальными ЦПУ и общее улучшение геометрического среднего на 7.4 %. Документация - в PR #50748.

  2. Параллельное слияние одноуровневых хеш-таблиц. Эта доработка расширила параллельное слияние для сценариев, где все хеш-таблицы находятся на одном уровне. Улучшение привело к росту производительности для таких случаев на 235 % без регрессий на небольших наборах данных. Подробнее см. PR #52973.

  3. Параллельное слияние с поддержкой ключей (GROUP BY). Расширение параллелизма на агрегации с ключами (GROUP BY) подняло запросы Q8 и Q9 из ClickBench на 10.3 % и 7.6 % соответственно. За счёт лучшей утилизации ЦПУ на фазе слияния удалось достичь этих улучшений. Подробности - в PR #68441.

Алгоритмические оптимизации

Применение SIMD-инструкций (Single Instruction, Multiple Data) может существенно ускорить работу, однако требует тщательной алгоритмической проработки.

  1. SIMD-поиск подстрок по двум символам. Исходный код ClickHouse для поиска подстрок проверял только первый символ, что приводило к множеству ложных срабатываний. Оптимизированная версия использует SIMD для одновременного сравнения первого и второго символов, значительно сокращая количество ложных срабатываний. Это дало ускорение запроса Q20 из ClickBench на 35 % и повысило общее геометрическое среднее на 4.1 %. Реализация размещена в PR #46289.

Борьба с ложным разделением кэша (False Sharing)

False sharing - явление, при котором конкуренция за одни и те же линии кэша, содержащие независимые данные, может сильно тормозить работу.

  1. Выравнивание счётчиков событий профилирования. На системе с 2×240 виртуальными ЦПУ 36.6 % процессорного времени уходило на ProfileEvents::increment из-за конкуренции за линии кэша. Было решено выровнять каждый счётчик до границы кэш-линии в 64 байта, предоставив каждому счётчику собственную линию. В результате доля ЦПУ, затрачиваемая на ProfileEvents::increment, упала до 8.5 %, а запрос Q3 из ClickBench получил ускорение на 27.4 %. Эта оптимизация описана в PR #82697.

Заключение

Предлагаемые Intel-оптимизации, находящиеся в основной ветке ClickHouse, показывают, как детальный анализ и инженерный подход позволяют достичь масштабируемости в системах с высокой плотностью ядер. Как подчёркивают авторы, описанные приёмы применимы не только к ClickHouse, но и к другим решениям, сталкивающимся с аналогичными задачами в эпоху многоядерных процессоров. Эти усилия, подкреплённые тесным сотрудничеством Intel и сообщества ClickHouse, обеспечили почти линейную масштабируемость при росте количества ядер, что критически важно для аналитических нагрузок на петабайтных объёмах данных в корпоративных и облачных средах. https://bigdataschool.ru/blog/news/clickhouse/clickhouse-cpu-multithreads/

Вопросы и ответы

ClickHouse: Глубокая оптимизация для высокоядерных процессоров Intel
Устранение конфликтов блокировок
Эффективное управление памятью
Увеличение параллелизма
Алгоритмические оптимизации
Борьба с ложным разделением кэша (False Sharing)
Заключение