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_logcon el tipoJemallocSamplepara 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.
Muestreo de asignaciones
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.
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>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.Vacía el system.trace_log:
SYSTEM FLUSH LOGS trace_logA 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_timeEncuentra 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 ASCUI web de jemalloc
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/jemallocLa UI del servidor incluye todas las pestañas: Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler y Raw Output.
http://localhost:9182/jemallocLa 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.
Keeper también expone endpoints de la API REST para acceso programático:
GET /jemalloc/stats— salida sin procesar demalloc_stats_printGET /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
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_textFormato de salida
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,jeprofpuede 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'Ajustes adicionales
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 formatossymbolizedycollapsed.jemalloc_profile_text_collapsed_use_count(Bool, valor predeterminado:false) — Al usar el formatocollapsed, 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.svgPara 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.svgVolcado 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 PROFILEDevolverá la ubicación del perfil volcado.
echo jmfp | nc localhost 9181Se 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_profileEl 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.shdesde la carpeta raíz. Esto le proporcionará el scriptjeprofdentro de la carpetabin
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 PROFILEClickHouse 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]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]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]Ejemplos
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.pdfUso 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.pdfGenerar un flame graph
jeprof permite generar collapsed stacks para crear flame graphs.
Debe usar el argumento --collapsed:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsedO con un perfil sin simbolizar:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsedDespué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.svgOtra 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.
Otros recursos
ClickHouse/Keeper exponen métricas relacionadas con jemalloc de muchas formas distintas.
Tabla del sistema asynchronous_metrics
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT VerticalTabla 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.
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_statsPrometheus
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.
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