O ClickHouse usa o jemalloc como alocador global. O jemalloc inclui ferramentas de amostragem e profiling de alocação.
O ClickHouse e o Keeper permitem controlar a amostragem usando configurações, configurações de consulta, comandos SYSTEM e comandos de quatro letras (4LW) no Keeper. Há várias maneiras de inspecionar os resultados:
- Coletar amostras em
system.trace_log sob o tipo JemallocSample para análise por consulta.
- Visualizar estatísticas de memória em tempo real e obter perfis de heap por meio da interface web integrada do jemalloc (26.2+).
- Consultar o perfil de heap atual diretamente via SQL usando
system.jemalloc_profile_text (26.2+).
- Gravar perfis de heap em disco e analisá-los com
jeprof.
Para fazer a amostragem e traçar o perfil das alocações, inicie o ClickHouse/Keeper com a configuração jemalloc_enable_global_profiler habilitada:
<clickhouse>
<jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>
jemalloc fará a amostragem das alocações e armazenará as informações internamente.
Você também pode ativar a amostragem por consulta usando a configuração jemalloc_enable_profiler.
AvisoComo o ClickHouse é um aplicativo com uso intensivo de alocação de memória, a amostragem do jemalloc pode causar sobrecarga de desempenho.
Armazenando amostras do jemalloc em system.trace_log
Você pode armazenar amostras do jemalloc em system.trace_log como o tipo JemallocSample.
Para habilitar isso globalmente, use a configuração 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>
AvisoComo o ClickHouse é uma aplicação que faz uso intensivo de alocações, coletar todas as amostras em system.trace_log pode gerar uma carga elevada.
Você também pode habilitar isso por consulta usando a configuração jemalloc_collect_profile_samples_in_trace_log.
Exemplo: analisando o uso de memória de uma consulta
Primeiro, execute uma consulta com o profiler do jemalloc habilitado e colete as amostras em 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.
Se o ClickHouse foi iniciado com jemalloc_enable_global_profiler, você não precisa habilitar jemalloc_enable_profiler.
O mesmo vale para jemalloc_collect_global_profile_samples_in_trace_log e jemalloc_collect_profile_samples_in_trace_log.
Faça o flush de system.trace_log:
SYSTEM FLUSH LOGS trace_log
Em seguida, consulte-o para obter o uso cumulativo de memória ao longo do tempo:
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
Encontre o momento em que o uso de memória foi mais 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
)
Usando esse resultado, veja quais pilhas de alocação estavam mais ativas no momento de pico:
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
Interface web do jemalloc
Esta seção se aplica às versões 26.2+.
O ClickHouse fornece uma interface web integrada para visualizar estatísticas de memória do jemalloc no endpoint HTTP /jemalloc.
Ela exibe métricas de memória em tempo real com gráficos, incluindo memória alocada, ativa, residente e mapeada, além de estatísticas por arena e por bin.
Você também pode buscar perfis de heap globais e por consulta diretamente pela interface web.
http://localhost:8123/jemalloc
A interface web do servidor inclui todas as abas: Summary, Allocations, Arenas, Operations, Global Profiler, Query Profiler e Raw Output.http://localhost:9182/jemalloc
A interface web do Keeper está disponível na porta de controle HTTP. Essa porta fica desabilitada por padrão e deve ser habilitada explicitamente definindo keeper_server.http_control.port na configuração do Keeper:<clickhouse>
<keeper_server>
<http_control>
<port>9182</port>
</http_control>
</keeper_server>
</clickhouse>
Depois de habilitada, a interface web fornece as mesmas visualizações que o servidor — Summary, Allocations, Arenas, Operations, Global Profiler e Raw Output — exceto pela aba Query Profiler, que requer SQL e system.trace_log.SegurançaA porta de controle HTTP do Keeper não tem autenticação no nível da aplicação. Diferentemente da interface web do jemalloc do ClickHouse Server — em que todas as consultas de dados passam pelo handler HTTP de SQL e exigem credenciais de usuário/senha — os endpoints da API REST do Keeper não exigem autenticação. Isso é consistente com outros endpoints de controle HTTP do Keeper (commands, storage, dashboard).Restrinja o acesso a essa porta usando controles no nível da rede: configure o Keeper para escutar em localhost, use regras de firewall ou coloque-o atrás de um proxy reverso com autenticação. Quando nenhum listen_host é configurado, o Keeper passa a escutar somente em localhost por padrão.
O Keeper também expõe endpoints de API REST para acesso programático:
GET /jemalloc/stats — saída bruta de malloc_stats_print
GET /jemalloc/status — estado do profiling em JSON (prof_enabled, prof_active, thread_active_init, lg_sample)
GET /jemalloc/profile?format={collapsed|raw} — gera um perfil de heap com simbolização no lado do servidor e retorna collapsed stacks adequadas para renderização de flame graph (padrão) ou o dump bruto do jemalloc
Obtendo perfis de heap por SQL
Esta seção se aplica às versões 26.2+.
A tabela de sistema system.jemalloc_profile_text permite obter e visualizar o perfil de heap atual do jemalloc diretamente por SQL, sem precisar de ferramentas externas nem de gravá-lo em disco antes.
A tabela tem uma única coluna:
| Coluna | Tipo | Descrição |
|---|
line | String | Linha do perfil de heap do jemalloc simbolizado. |
Você pode consultar a tabela diretamente — não é necessário gravar um perfil de heap antes:
SELECT * FROM system.jemalloc_profile_text
O formato de saída é controlado pela configuração jemalloc_profile_text_output_format, que oferece suporte a três valores:
raw — perfil de heap bruto, gerado pelo jemalloc.
symbolized — formato compatível com o jeprof, com símbolos de função incorporados. Como os símbolos já estão incorporados, o jeprof pode analisar a saída sem precisar do binário do ClickHouse.
collapsed (padrão) — pilhas colapsadas compatíveis com FlameGraph, uma pilha por linha com a contagem de bytes.
Por exemplo, para obter o perfil bruto:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'
Para obter uma saída simbolizada:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'
jemalloc_profile_text_symbolize_with_inline (Bool, padrão: true) — Define se frames inline devem ser incluídos na simbolização. Desabilitar isso acelera significativamente a simbolização, mas reduz a precisão, pois chamadas de função inline não aparecerão nas stacks. Afeta apenas os formatos symbolized e collapsed.
jemalloc_profile_text_collapsed_use_count (Bool, padrão: false) — Ao usar o formato collapsed, agrega por contagem de alocações em vez de bytes.
Como o formato de saída padrão é collapsed, você pode passar a saída diretamente para o FlameGraph:
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
Para gerar um flame graph com base na contagem de alocações, em vez de 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
Gravando perfis de heap no disco
Se você precisar salvar perfis de heap como arquivos para análise offline com jeprof, poderá gravá-los no disco.
Por padrão, o arquivo de perfil de heap será gerado em /tmp/jemalloc_clickhouse._pid_._seqnum_.heap, em que _pid_ é o PID do ClickHouse e _seqnum_ é o número de sequência global do perfil de heap atual.
No Keeper, o arquivo padrão é /tmp/jemalloc_keeper._pid_._seqnum_.heap e segue as mesmas regras.
Para gravar o perfil atual:
SYSTEM JEMALLOC FLUSH PROFILE
Ele retornará o local do perfil gravado.echo jmfp | nc localhost 9181
É possível definir outro local adicionando a opção prof_prefix à variável de ambiente MALLOC_CONF.
Por exemplo, se você quiser gerar perfis na pasta /data, em que o prefixo do nome do arquivo será my_current_profile, poderá executar o ClickHouse/Keeper com a seguinte variável de ambiente:
MALLOC_CONF=prof_prefix:/data/my_current_profile
O PID e o número de sequência serão acrescentados ao prefixo do arquivo gerado.
Após gravar os perfis de heap em disco, eles podem ser analisados usando a ferramenta do jemalloc chamada jeprof. Ela pode ser instalada de várias formas:
- Usando o gerenciador de pacotes do sistema
- Clonando o repositório do jemalloc e executando
autogen.sh a partir da pasta raiz. Isso disponibilizará o script jeprof na pasta bin
Há vários formatos de saída disponíveis. Execute jeprof --help para ver a lista completa de opções.
Perfis de heap simbolizados
A partir da versão 26.1+, o ClickHouse gera automaticamente perfis de heap simbolizados quando você executa SYSTEM JEMALLOC FLUSH PROFILE.
O perfil simbolizado (com a extensão .symbolized) contém símbolos de função incorporados e pode ser analisado com o jeprof sem exigir o binário do ClickHouse.
Por exemplo, quando você executa:
SYSTEM JEMALLOC FLUSH PROFILE
O ClickHouse retornará o caminho para o profile simbolizado (por exemplo, /tmp/jemalloc_clickhouse.12345.0.heap.symbolized).
Em seguida, você poderá analisá-lo diretamente com jeprof:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]
Nenhum binário necessário: Ao usar perfis simbolizados (arquivos .symbolized), você não precisa fornecer o caminho do binário do ClickHouse ao jeprof. Isso facilita muito a análise de perfis em máquinas diferentes ou depois que o binário tiver sido atualizado.
Se você tiver um perfil de heap mais antigo, sem símbolos, e ainda tiver acesso ao binário do ClickHouse, poderá usar a abordagem tradicional:
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]
Para perfis não simbolizados, jeprof usa addr2line para gerar stacktraces, o que pode ser bem lento.
Se esse for o caso, recomenda-se instalar uma implementação alternativa da ferramenta.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 igualmente bem (mas observe que llvm-objdump não é compatível com jeprof)Depois, use-o assim: jeprof --tools addr2line:/usr/bin/llvm-addr2line,nm:/usr/bin/llvm-nm,objdump:/usr/bin/objdump,c++filt:/usr/bin/llvm-cxxfilt
Ao comparar dois perfis, você pode usar o argumento --base:
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]
Usando perfis simbolizados (recomendado):
- Gere um arquivo de texto com cada procedimento em uma linha:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt
- Gere um arquivo PDF com o grafo de chamadas:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdf
Usando perfis não simbolizados (requer o binário):
- Gere um arquivo de texto com cada procedimento em uma linha:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt
- Gere um arquivo PDF com um grafo de chamadas:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdf
jeprof permite gerar pilhas colapsadas para criar flame graphs.
Você precisa usar o argumento --collapsed:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsed
Ou com um perfil sem símbolos:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsed
Depois disso, você pode usar várias ferramentas para visualizar pilhas colapsadas.
A mais popular é o FlameGraph, que contém um script chamado flamegraph.pl:
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svg
Outra ferramenta interessante é o speedscope, que permite analisar as stacks coletadas de forma mais interativa.
Opções adicionais para o profiler
O jemalloc oferece muitas opções relacionadas ao profiler. Elas podem ser controladas modificando a variável de ambiente MALLOC_CONF.
Por exemplo, o intervalo entre as amostras de alocação pode ser controlado com lg_prof_sample.
Se você quiser gerar o heap profile a cada N bytes, pode ativá-lo usando lg_prof_interval.
Recomenda-se consultar a página de referência do jemalloc para obter uma lista completa das opções.
ClickHouse/Keeper expõem métricas relacionadas ao jemalloc de várias formas.
AvisoÉ importante ter em mente que nenhuma dessas métricas é sincronizada com as outras, e os valores podem divergir.
Tabela de sistema asynchronous_metrics
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Vertical
Referência
Tabela de sistema jemalloc_bins
Contém informações sobre alocações de memória feitas pelo alocador jemalloc em diferentes classes de tamanho (bins), agregadas a partir de todas as arenas.
Referência
Tabela do sistema jemalloc_stats (26.2+)
Retorna toda a saída de malloc_stats_print() como uma única string. Equivalente ao comando SYSTEM JEMALLOC STATS.
SELECT * FROM system.jemalloc_stats
Todas as métricas relacionadas ao jemalloc de asynchronous_metrics também são expostas por meio do endpoint do Prometheus, tanto no ClickHouse quanto no Keeper.
Referência
Comando 4LW jmst no Keeper
O Keeper é compatível com o comando 4LW jmst, que retorna estatísticas básicas do alocador:
echo jmst | nc localhost 9181