ClickHouse usa jemalloc como asignador global. Jemalloc incluye herramientas para el muestreo y el perfilado de asignaciones.
ClickHouse y Keeper permiten controlar el muestreo mediante configuraciones, settings de consulta, comandos SYSTEM y comandos de cuatro letras (4LW) en Keeper. Hay varias formas de inspeccionar los resultados:
- Recopilar muestras en
system.trace_log con el tipo JemallocSample para analizar cada consulta.
- Ver estadísticas de memoria en tiempo real y obtener perfiles de heap a través de la UI web de jemalloc integrada (26.2+).
- Consultar el perfil actual de heap directamente desde SQL mediante
system.jemalloc_profile_text (26.2+).
- Volcar perfiles de heap a disco y analizarlos con
jeprof.
Para muestrear y perfilar las asignaciones, inicie ClickHouse/Keeper con la opción de configuración jemalloc_enable_global_profiler habilitada:
<clickhouse>
<jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>
jemalloc realizará un muestreo de las asignaciones y almacenará la información internamente.
También puede habilitar el muestreo por consulta mediante la configuración jemalloc_enable_profiler.
AdvertenciaDado que ClickHouse es una aplicación que realiza muchas asignaciones de memoria, el muestreo de jemalloc puede introducir una sobrecarga de rendimiento.
Almacenar muestras de jemalloc en system.trace_log
Puede almacenar muestras de jemalloc en system.trace_log con el tipo JemallocSample.
Para habilitarlo globalmente, use la configuración jemalloc_collect_global_profile_samples_in_trace_log:
<clickhouse>
<jemalloc_collect_global_profile_samples_in_trace_log>1</jemalloc_collect_global_profile_samples_in_trace_log>
</clickhouse>
AdvertenciaDado que ClickHouse es una aplicación que realiza muchas asignaciones de memoria, recopilar todas las muestras en system.trace_log puede generar una carga elevada.
También puede habilitarse para cada consulta mediante la configuración jemalloc_collect_profile_samples_in_trace_log.
Ejemplo: analizar el uso de memoria de una consulta
Primero, ejecute una consulta con el perfilador de jemalloc habilitado y recopile las muestras en system.trace_log:
SELECT *
FROM numbers(1000000)
ORDER BY number DESC
SETTINGS max_bytes_ratio_before_external_sort = 0
FORMAT `Null`
SETTINGS jemalloc_enable_profiler = 1, jemalloc_collect_profile_samples_in_trace_log = 1
Query id: 8678d8fe-62c5-48b8-b0cd-26851c62dd75
Ok.
0 rows in set. Elapsed: 0.009 sec. Processed 1.00 million rows, 8.00 MB (108.58 million rows/s., 868.61 MB/s.)
Peak memory usage: 12.65 MiB.
Si ClickHouse se inició con jemalloc_enable_global_profiler, no es necesario habilitar jemalloc_enable_profiler.
Lo mismo ocurre con jemalloc_collect_global_profile_samples_in_trace_log y jemalloc_collect_profile_samples_in_trace_log.
Vacía el system.trace_log:
SYSTEM FLUSH LOGS trace_log
A continuación, consúltalo para obtener el uso acumulado de memoria a lo largo del tiempo:
WITH per_bucket AS
(
SELECT
event_time_microseconds AS bucket_time,
sum(size) AS bucket_sum
FROM system.trace_log
WHERE trace_type = 'JemallocSample'
AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
GROUP BY bucket_time
)
SELECT
bucket_time,
sum(bucket_sum) OVER (
ORDER BY bucket_time ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_size,
formatReadableSize(cumulative_size) AS cumulative_size_readable
FROM per_bucket
ORDER BY bucket_time
Encuentra el momento en que el uso de memoria fue más alto:
SELECT
argMax(bucket_time, cumulative_size),
max(cumulative_size)
FROM
(
WITH per_bucket AS
(
SELECT
event_time_microseconds AS bucket_time,
sum(size) AS bucket_sum
FROM system.trace_log
WHERE trace_type = 'JemallocSample'
AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
GROUP BY bucket_time
)
SELECT
bucket_time,
sum(bucket_sum) OVER (
ORDER BY bucket_time ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cumulative_size,
formatReadableSize(cumulative_size) AS cumulative_size_readable
FROM per_bucket
ORDER BY bucket_time
)
Con ese resultado, vea qué pilas de asignación estuvieron más activas en el punto máximo:
SELECT
concat(
'\n',
arrayStringConcat(
arrayMap(
(x, y) -> concat(x, ': ', y),
arrayMap(x -> addressToLine(x), allocation_trace),
arrayMap(x -> demangle(addressToSymbol(x)), allocation_trace)
),
'\n'
)
) AS symbolized_trace,
sum(s) AS per_trace_sum
FROM
(
SELECT
ptr,
sum(size) AS s,
argMax(trace, event_time_microseconds) AS allocation_trace
FROM system.trace_log
WHERE trace_type = 'JemallocSample'
AND query_id = '8678d8fe-62c5-48b8-b0cd-26851c62dd75'
AND event_time_microseconds <= '2025-09-04 11:56:21.737139'
GROUP BY ptr
HAVING s > 0
)
GROUP BY ALL
ORDER BY per_trace_sum ASC
Esta sección se aplica a las versiones 26.2 o posteriores.
ClickHouse proporciona una UI web integrada para ver las estadísticas de memoria de jemalloc en el endpoint HTTP /jemalloc.
Muestra métricas de memoria en tiempo real con gráficos, incluidas allocated, active, resident y mapped, así como estadísticas por arena y por bin.
También puedes obtener perfiles de heap globales y por consulta directamente desde la UI.
http://localhost:8123/jemalloc
La UI del servidor incluye todas las pestañas: Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler y Raw Output.http://localhost:9182/jemalloc
La UI de Keeper está disponible en el puerto de control HTTP. Este puerto está deshabilitado de forma predeterminada y debe habilitarse explícitamente configurando keeper_server.http_control.port en la configuración de Keeper:<clickhouse>
<keeper_server>
<http_control>
<port>9182</port>
</http_control>
</keeper_server>
</clickhouse>
Una vez habilitada, la UI ofrece las mismas visualizaciones que el servidor — Summary, Allocations, Arenas, Operations, Global Profiler y Raw Output — excepto la pestaña Query Profiler, que requiere SQL y system.trace_log.SeguridadEl puerto de control HTTP de Keeper no tiene autenticación a nivel de aplicación. A diferencia de la UI de jemalloc de ClickHouse Server — donde todas las consultas de datos pasan por el manejador HTTP de SQL y requieren credenciales de usuario/contraseña — los endpoints de la API REST de Keeper no requieren autenticación. Esto es coherente con otros endpoints de control HTTP de Keeper (commands, storage, dashboard).Restringe el acceso a este puerto mediante controles de red: vincula Keeper a localhost, usa reglas de firewall o colócalo detrás de un proxy inverso con autenticación. Si no se configura listen_host, Keeper escucha únicamente en localhost de forma predeterminada.
Keeper también expone endpoints de la API REST para acceso programático:
GET /jemalloc/stats — salida sin procesar de malloc_stats_print
GET /jemalloc/status — estado del profiling en JSON (prof_enabled, prof_active, thread_active_init, lg_sample)
GET /jemalloc/profile?format={collapsed|raw} — hace flush de un perfil de heap con simbolización en el servidor; devuelve collapsed stacks aptas para renderizar flame graphs (predeterminado) o el dump sin procesar de jemalloc
Obtención de perfiles de heap desde SQL
Esta sección se aplica a las versiones 26.2+.
La tabla del sistema system.jemalloc_profile_text permite obtener y ver el perfil de heap actual de jemalloc directamente desde SQL, sin necesidad de herramientas externas ni de volcarlo antes a disco.
La tabla tiene una sola columna:
| Columna | Tipo | Descripción |
|---|
line | String | Línea del perfil de heap de jemalloc simbolizado. |
Puede consultar la tabla directamente; no es necesario volcar antes un perfil de heap:
SELECT * FROM system.jemalloc_profile_text
El formato de salida se controla mediante la configuración jemalloc_profile_text_output_format, que admite tres valores:
raw — perfil de heap en bruto, tal como lo genera jemalloc.
symbolized — formato compatible con jeprof con símbolos de función integrados. Como los símbolos ya están integrados, jeprof puede analizar la salida sin necesidad del binario de ClickHouse.
collapsed (predeterminado) — collapsed stacks compatibles con FlameGraph, una pila por línea con el recuento de bytes.
Por ejemplo, para obtener el perfil en bruto:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'
Para obtener una salida simbolizada:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'
jemalloc_profile_text_symbolize_with_inline (Bool, valor predeterminado: true) — Indica si se deben incluir los frames inline al simbolizar. Desactivarlo acelera significativamente la simbolización, pero reduce la precisión, ya que las llamadas a funciones inline no aparecerán en los stacks. Solo afecta a los formatos symbolized y collapsed.
jemalloc_profile_text_collapsed_use_count (Bool, valor predeterminado: false) — Al usar el formato collapsed, agrupa por número de asignaciones en lugar de por bytes.
Ejemplo: generar un flame graph desde SQL
Dado que el formato de salida predeterminado es collapsed, puedes redirigir la salida directamente a FlameGraph:
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
Para generar un flame graph según el recuento de asignaciones en lugar de por bytes:
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text SETTINGS jemalloc_profile_text_collapsed_use_count = 1" | flamegraph.pl --color=mem --title="Allocation Count Flame Graph" --width 2400 > result.svg
Volcado de perfiles de heap a disco
Si necesitas guardar perfiles de heap como archivos para analizarlos sin conexión con jeprof, puedes volcarlos a disco.
De forma predeterminada, el archivo del perfil de heap se generará en /tmp/jemalloc_clickhouse._pid_._seqnum_.heap, donde _pid_ es el PID de ClickHouse y _seqnum_ es el número de secuencia global del perfil de heap actual.
Para Keeper, el archivo predeterminado es /tmp/jemalloc_keeper._pid_._seqnum_.heap y sigue las mismas reglas.
Para volcar el perfil actual:
SYSTEM JEMALLOC FLUSH PROFILE
Devolverá la ubicación del perfil volcado.echo jmfp | nc localhost 9181
Se puede definir una ubicación diferente añadiendo la opción prof_prefix a la variable de entorno MALLOC_CONF.
Por ejemplo, si quieres generar perfiles en la carpeta /data, donde el prefijo del nombre de archivo será my_current_profile, puedes ejecutar ClickHouse/Keeper con la siguiente variable de entorno:
MALLOC_CONF=prof_prefix:/data/my_current_profile
El archivo generado se añadirá al prefijo, al PID y al número de secuencia.
Análisis de archivos de perfiles de heap con jeprof
Después de volcar los perfiles de heap en disco, se pueden analizar con la herramienta de jemalloc llamada jeprof. Se puede instalar de varias maneras:
- Usando el gestor de paquetes del sistema
- Clonando el repositorio de jemalloc y ejecutando
autogen.sh desde la carpeta raíz. Esto le proporcionará el script jeprof dentro de la carpeta bin
Hay varios formatos de salida disponibles. Ejecute jeprof --help para ver la lista completa de opciones.
Perfiles de heap simbolizados
A partir de la versión 26.1+, ClickHouse genera automáticamente perfiles de heap simbolizados al ejecutar SYSTEM JEMALLOC FLUSH PROFILE.
El perfil simbolizado (con la extensión .symbolized) contiene símbolos de función integrados y puede analizarse con jeprof sin necesidad del binario de ClickHouse.
Por ejemplo, cuando ejecutas:
SYSTEM JEMALLOC FLUSH PROFILE
ClickHouse devolverá la ruta al perfil simbolizado (p. ej., /tmp/jemalloc_clickhouse.12345.0.heap.symbolized).
Luego puedes analizarlo directamente con jeprof:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]
No se requiere el binario: Al usar perfiles simbolizados (archivos .symbolized), no necesitas proporcionar a jeprof la ruta del binario de ClickHouse. Esto facilita mucho el análisis de perfiles en distintas máquinas o después de actualizar el binario.
Si tienes un heap profile no simbolizado más antiguo y todavía tienes acceso al binario de ClickHouse, puedes usar el enfoque tradicional:
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]
Para perfiles no simbolizados, jeprof usa addr2line para generar stacktraces, lo que puede ser bastante lento.
Si es así, se recomienda instalar una implementación alternativa de la herramienta.git clone https://github.com/gimli-rs/addr2line.git --depth=1 --branch=0.23.0
cd addr2line
cargo build --features bin --release
cp ./target/release/addr2line path/to/current/addr2line
Como alternativa, llvm-addr2line funciona igual de bien (pero tenga en cuenta que llvm-objdump no es compatible con jeprof).Y después úselo así: jeprof --tools addr2line:/usr/bin/llvm-addr2line,nm:/usr/bin/llvm-nm,objdump:/usr/bin/objdump,c++filt:/usr/bin/llvm-cxxfilt
Al comparar dos perfiles, puede usar el argumento --base:
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]
Con perfiles simbolizados (recomendado):
- Genere un archivo de texto con cada procedimiento en una línea:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt
- Genera un archivo PDF con el grafo de llamadas:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdf
Uso de perfiles sin simbolizar (requiere el binario):
- Genere un archivo de texto con un procedimiento por línea:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt
- Genera un archivo PDF con un grafo de llamadas:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdf
jeprof permite generar collapsed stacks para crear flame graphs.
Debe usar el argumento --collapsed:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsed
O con un perfil sin simbolizar:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsed
Después, puedes usar muchas herramientas distintas para visualizar collapsed stacks.
La más popular es FlameGraph, que incluye un script llamado flamegraph.pl:
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
Otra herramienta interesante es speedscope, que te permite analizar los stacks recopilados de forma más interactiva.
Opciones adicionales para el perfilador
jemalloc ofrece muchas opciones relacionadas con el perfilador. Se pueden controlar modificando la variable de entorno MALLOC_CONF.
Por ejemplo, el intervalo entre muestras de asignación puede controlarse con lg_prof_sample.
Si desea volcar el perfil de heap cada N bytes, puede habilitarlo con lg_prof_interval.
Se recomienda consultar la página de referencia de jemalloc para ver la lista completa de opciones.
ClickHouse/Keeper exponen métricas relacionadas con jemalloc de muchas formas distintas.
AdvertenciaEs importante tener en cuenta que ninguna de estas métricas está sincronizada con las demás y que los valores pueden diferir.
Tabla del sistema asynchronous_metrics
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Vertical
Referencia
Tabla del sistema jemalloc_bins
Contiene información sobre las asignaciones de memoria realizadas mediante el asignador jemalloc en distintas clases de tamaño (bins), agregadas de todas las arenas.
Referencia
Tabla del sistema jemalloc_stats (26.2+)
Devuelve la salida completa de malloc_stats_print() en una sola cadena. Equivale al comando SYSTEM JEMALLOC STATS.
SELECT * FROM system.jemalloc_stats
Todas las métricas relacionadas con jemalloc de asynchronous_metrics también están expuestas a través del endpoint de Prometheus tanto en ClickHouse como en Keeper.
Referencia
Comando 4LW jmst de Keeper
Keeper admite el comando 4LW jmst, que devuelve estadísticas básicas del asignador de memoria:
echo jmst | nc localhost 9181