Профилирование выделений памяти
ClickHouse использует jemalloc в качестве глобального аллокатора. Jemalloc предоставляет инструменты для сэмплирования и профилирования выделений памяти.
Чтобы сделать профилирование выделений более удобным, ClickHouse и Keeper позволяют управлять сэмплированием с помощью конфигурационных файлов, настроек запроса, команд SYSTEM и четырёхбуквенных (4LW) команд в Keeper.
Кроме того, сэмплы могут записываться в таблицу system.trace_log с типом JemallocSample.
Это руководство применимо к версиям 25.9 и новее. Для более старых версий см. раздел профилирование выделений для версий до 25.9.
Сэмплирование выделений памяти
Если вы хотите выполнять сэмплирование и профилирование выделений памяти в jemalloc, необходимо запускать ClickHouse/Keeper с включённой настройкой конфигурации jemalloc_enable_global_profiler.
jemalloc будет выборочно отслеживать выделения памяти и сохранять эту информацию во внутренних структурах.
Вы также можете включить профилирование выделений памяти по каждому запросу с помощью настройки jemalloc_enable_profiler.
Поскольку ClickHouse — приложение с интенсивным использованием выделения памяти, выборочное отслеживание jemalloc может привести к дополнительным накладным расходам и снижению производительности.
Хранение выборок jemalloc в system.trace_log
Вы можете хранить все выборки jemalloc в system.trace_log с типом записи JemallocSample.
Чтобы включить это глобально, используйте параметр конфигурации jemalloc_collect_global_profile_samples_in_trace_log.
Поскольку ClickHouse — приложение с большим количеством операций выделения памяти, сбор всех сэмплов в system.trace_log может привести к значительной нагрузке.
Вы также можете включить это для отдельного запроса, используя настройку jemalloc_collect_profile_samples_in_trace_log.
Пример анализа использования памяти запросом с помощью system.trace_log
Сначала нам нужно выполнить запрос с включённым профилировщиком памяти jemalloc и собрать для него сэмплы в system.trace_log:
Если ClickHouse был запущен с jemalloc_enable_global_profiler, вам не нужно включать jemalloc_enable_profiler.
То же самое относится к jemalloc_collect_global_profile_samples_in_trace_log и jemalloc_collect_profile_samples_in_trace_log.
Очистим system.trace_log:
и выполнять к нему запрос, чтобы получить потребление памяти нашим запросом для каждого момента времени:
Мы также можем найти момент времени, когда использование памяти достигало максимума:
Мы можем использовать этот результат, чтобы увидеть, откуда шло больше всего активных выделений памяти в тот момент времени:
Сброс профилей кучи
По умолчанию файл профиля кучи создаётся в /tmp/jemalloc_clickhouse._pid_._seqnum_.heap, где _pid_ — это PID ClickHouse, а _seqnum_ — глобальный порядковый номер для текущего профиля кучи.
Для Keeper файл по умолчанию — /tmp/jemalloc_keeper._pid_._seqnum_.heap и подчиняется тем же правилам.
Вы можете попросить jemalloc сбросить текущий профиль, выполнив:
- ClickHouse
- Keeper
Команда вернёт путь к сброшенному профилю.
Другое местоположение можно задать, дополнив переменную окружения MALLOC_CONF опцией prof_prefix.
Например, если вы хотите генерировать профили в каталоге /data, где префиксом имени файла будет my_current_profile, вы можете запустить ClickHouse/Keeper со следующей переменной окружения:
К имени сгенерированного файла будет добавлен префикс с PID и порядковым номером.
Анализ профилей кучи
После того как профили кучи были сгенерированы, их необходимо проанализировать.
Для этого можно использовать инструмент jemalloc под названием jeprof. Его можно установить несколькими способами:
- С помощью системного менеджера пакетов
- Клонировать репозиторий jemalloc и запустить
autogen.shиз корневого каталога. В результате в каталогеbinпоявится скриптjeprof.
jeprof использует addr2line для генерации стек-трейсов, что может работать очень медленно.
В таком случае рекомендуется установить альтернативную реализацию этого инструмента.
В качестве альтернативы llvm-addr2line работает так же эффективно.
Существует множество различных форматов, которые можно получить из профиля кучи с помощью jeprof.
Рекомендуется запустить jeprof --help, чтобы получить информацию об использовании и о различных опциях, которые предоставляет этот инструмент.
В целом команду jeprof обычно используют следующим образом:
Если вы хотите сравнить, какие выделения памяти произошли между двумя профилями, укажите аргумент base:
Примеры
- если вы хотите сгенерировать текстовый файл, в котором каждая процедура будет записана в отдельной строке:
- если вы хотите сгенерировать PDF-файл с графом вызовов:
Построение flame-графа
jeprof позволяет получать свернутые стеки вызовов для построения flame-графов.
Для этого следует использовать аргумент --collapsed:
После этого вы можете использовать различные инструменты для визуализации свернутых стеков.
Самый популярный из них — FlameGraph, который содержит скрипт flamegraph.pl:
Еще один полезный инструмент — speedscope, который позволяет анализировать собранные стеки в более интерактивном режиме.
Дополнительные параметры профилировщика
У jemalloc есть множество параметров, относящихся к профилировщику. Ими можно управлять, изменяя переменную окружения MALLOC_CONF.
Например, интервал между выборками операций выделения памяти можно контролировать с помощью lg_prof_sample.
Если вы хотите создавать дамп профиля кучи каждые N байт, вы можете включить это с помощью lg_prof_interval.
Рекомендуется ознакомиться со справочной страницей jemalloc для получения полного перечня параметров.
Другие ресурсы
ClickHouse/Keeper предоставляют метрики, связанные с jemalloc, множеством разных способов.
Важно понимать, что ни одна из этих метрик не синхронизирована с другими, и значения со временем могут расходиться.
Системная таблица asynchronous_metrics
Системная таблица jemalloc_bins
Содержит информацию о выделении памяти, выполненном через аллокатор jemalloc в разных классах размеров (bins), агрегированную по всем аренам.
Prometheus
Все метрики, связанные с jemalloc из asynchronous_metrics, также доступны через конечную точку Prometheus как в ClickHouse, так и в Keeper.
Команда jmst 4LW в Keeper
Keeper поддерживает команду jmst 4LW, которая возвращает базовую статистику аллокатора: