ClickHouse はグローバルアロケータとして jemalloc を使用しています。jemalloc には、割り当てのサンプリングやプロファイリングのためのツールが含まれています。
ClickHouse と Keeper では、設定ファイル、クエリ設定、SYSTEM コマンド、および Keeper の four letter word (4LW) コマンドを使ってサンプリングを制御できます。結果を確認する方法はいくつかあります。
- クエリごとの分析のために、
JemallocSampleタイプとしてサンプルをsystem.trace_logに収集します。 - 組み込みの jemalloc web UI を使って、リアルタイムのメモリ統計を表示し、ヒーププロファイルを取得します (26.2+) 。
system.jemalloc_profile_textを使用して、現在のヒーププロファイルを SQL から直接クエリできます (26.2+) 。- ヒーププロファイルをディスクに flush し、
jeprofで解析します。
メモリ割り当てのサンプリング
メモリ割り当てをサンプリングしてプロファイリングするには、jemalloc_enable_global_profiler 設定を有効にして ClickHouse/Keeper を起動します。
<clickhouse>
<jemalloc_enable_global_profiler>1</jemalloc_enable_global_profiler>
</clickhouse>jemalloc は割り当てをサンプリングし、その情報を内部的に保存します。
jemalloc_enable_profiler 設定を使用すると、クエリごとにサンプリングを有効にすることもできます。
jemallocのサンプルをsystem.trace_logに保存する
jemallocのサンプルは、JemallocSampleタイプでsystem.trace_logに保存できます。
これをグローバルに有効化するには、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>jemalloc_collect_profile_samples_in_trace_log 設定を使うと、これをクエリごとに有効にすることもできます。
例: クエリのメモリ使用量を分析する
まず、jemallocプロファイラを有効にしてクエリを実行し、サンプルを 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.system.trace_log をフラッシュします:
SYSTEM FLUSH LOGS trace_log次に、これに対してクエリを実行し、時間の経過に伴う累積メモリ使用量を取得します。
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メモリ使用量が最も高かった時刻を確認します:
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
)その結果を使って、ピーク時に最も多くの割り当てを行っていたスタックを確認します。
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 ASCJemalloc web UI
ClickHouse には、/jemalloc HTTP エンドポイントで jemalloc のメモリ統計を表示する組み込みの web UI があります。
allocated、active、resident、mapped memory に加え、アリーナごとおよび bin ごとの統計を含むライブのメモリメトリクスが、チャートで表示されます。
また、グローバルおよびクエリごとのヒーププロファイルを UI から直接取得することもできます。
http://localhost:8123/jemallocサーバー UI には、Summary、Allocations、Arenas、Operations、Global Profiler、Query Profiler、Raw Output のすべてのタブが含まれています。
http://localhost:9182/jemallocKeeper UI は HTTP control port で利用できます。このポートはデフォルトで無効になっており、Keeper の設定で keeper_server.http_control.port を設定して明示的に有効にする必要があります。
<clickhouse>
<keeper_server>
<http_control>
<port>9182</port>
</http_control>
</keeper_server>
</clickhouse>有効にすると、この UI ではサーバーと同じ可視化、つまり Summary、Allocations、Arenas、Operations、Global Profiler、Raw Output が利用できます。ただし、Query Profiler タブは SQL と system.trace_log を必要とするため除きます。
Keeper は、プログラムからアクセスするための REST API エンドポイントも公開しています。
GET /jemalloc/stats— 生のmalloc_stats_print出力GET /jemalloc/status— JSON 形式の profiling state (prof_enabled、prof_active、thread_active_init、lg_sample)GET /jemalloc/profile?format={collapsed|raw}— サーバー側で symbolization を行ってヒーププロファイルを flush し、フレームグラフの描画に適したコラプスされたスタック (デフォルト) または生の jemalloc dump を返します
SQL からヒーププロファイルを取得する
system.jemalloc_profile_text システムテーブルを使用すると、外部ツールを使ったり、事前にディスクへフラッシュしたりしなくても、現在の jemalloc ヒーププロファイルを SQL から直接取得して確認できます。
このテーブルには 1 つのカラムがあります。
| Column | Type | Description |
|---|---|---|
line |
String | シンボル化された jemalloc ヒーププロファイルの行。 |
このテーブルには直接クエリできます。事前にヒーププロファイルをフラッシュする必要はありません。
SELECT * FROM system.jemalloc_profile_text出力フォーマット
出力フォーマットは jemalloc_profile_text_output_format 設定で制御され、次の 3 つの値をサポートしています。
raw— jemalloc によって生成される生のヒーププロファイル。symbolized— 関数シンボルが埋め込まれたjeprof互換フォーマットです。シンボルはすでに埋め込まれているため、jeprofは ClickHouse バイナリがなくても出力を解析できます。collapsed(デフォルト) — フレームグラフ互換のコラプスされたスタックです。各行に 1 つのスタックとバイト数が含まれます。
たとえば、生のプロファイルを取得するには次のようにします。
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'raw'シンボル化された出力を取得するには:
SELECT * FROM system.jemalloc_profile_text
SETTINGS jemalloc_profile_text_output_format = 'symbolized'追加設定
jemalloc_profile_text_symbolize_with_inline(Bool, デフォルト:true) — シンボル化の際にインラインフレームを含めるかどうかを指定します。これを無効にするとシンボル化は大幅に高速化されますが、インライン化された関数呼び出しがスタックに表示されなくなるため、精度は低下します。影響するのはsymbolizedおよびcollapsedフォーマットのみです。jemalloc_profile_text_collapsed_use_count(Bool, デフォルト:false) —collapsedフォーマットを使用する場合、バイト数ではなく割り当て回数で集計します。
例: SQLからフレームグラフを生成する
デフォルトの出力フォーマットは collapsed なので、出力をそのまま FlameGraph に渡せます:
clickhouse-client -q "SELECT * FROM system.jemalloc_profile_text" | flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svgバイト数ではなく、割り当て回数ベースで flame graph を生成するには:
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ヒーププロファイルをディスクにフラッシュする
jeprof を使ってヒーププロファイルをファイルとして保存し、オフラインで解析したい場合は、ディスクにフラッシュできます。
デフォルトでは、ヒーププロファイルファイルは /tmp/jemalloc_clickhouse._pid_._seqnum_.heap に生成されます。ここで、_pid_ は ClickHouse の PID、_seqnum_ は現在のヒーププロファイルのグローバルなシーケンス番号です。
Keeper の場合、デフォルトのファイルは /tmp/jemalloc_keeper._pid_._seqnum_.heap で、同じルールに従います。
現在のプロファイルをフラッシュするには、次のようにします。
SYSTEM JEMALLOC FLUSH PROFILEフラッシュされたプロファイルの保存場所が返されます。
echo jmfp | nc localhost 9181別の場所を指定するには、MALLOC_CONF 環境変数に prof_prefix オプションを追加します。
たとえば、ファイル名のプレフィックスを my_current_profile にして /data フォルダにプロファイルを生成する場合は、次の環境変数を指定して ClickHouse/Keeper を実行できます。
MALLOC_CONF=prof_prefix:/data/my_current_profile生成されるファイル名には、プレフィックス、PID、シーケンス番号が付加されます。
jeprof によるヒーププロファイルファイルの分析
ヒーププロファイルをディスクにフラッシュした後は、jemalloc のツールである jeprof を使って分析できます。インストール方法はいくつかあります。
- システムのパッケージマネージャーを使用する
- jemalloc リポジトリ をクローンし、ルートディレクトリで
autogen.shを実行する。これにより、binフォルダー内のjeprofスクリプトを利用できます
利用可能な出力フォーマットは多数あります。オプションの一覧は、jeprof --help を実行して確認してください。
シンボル化されたヒーププロファイル
バージョン 26.1 以降では、SYSTEM JEMALLOC FLUSH PROFILE を使ってフラッシュすると、ClickHouse はシンボル化されたヒーププロファイルを自動的に生成します。
シンボル化プロファイル (.symbolized 拡張子) には関数シンボルが埋め込まれているため、ClickHouse バイナリがなくても jeprof で解析できます。
たとえば、次を実行すると:
SYSTEM JEMALLOC FLUSH PROFILEClickHouse は、シンボル化されたプロファイルのパス (例: /tmp/jemalloc_clickhouse.12345.0.heap.symbolized) を返します。
続いて、jeprof を使って直接解析できます:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --output_format [ > output_file]古い未シンボル化のヒーププロファイルがあり、なおかつ ClickHouse バイナリに引き続きアクセスできる場合は、従来の方法を使用できます。
jeprof path/to/clickhouse path/to/heap/profile --output_format [ > output_file]2 つのプロファイルを比較する場合は、--base 引数を使用できます。
jeprof --base /path/to/first.heap.symbolized /path/to/second.heap.symbolized --output_format [ > output_file]例
シンボル化済みのプロファイルを使用する場合 (推奨) :
- 各プロシージャを1行に1つずつ記述したテキストファイルを生成します:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --text > result.txt- コールグラフ付きのPDFファイルを生成します:
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --pdf > result.pdfシンボル化されていないプロファイルを使用する場合 (バイナリが必要です) :
- 各プロシージャを1行に1つずつ記述したテキストファイルを生成します:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --text > result.txt- コールグラフを含むPDFファイルを生成します:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --pdf > result.pdfフレームグラフの生成
jeprof を使うと、フレームグラフの作成に使うコラプスされたスタックを生成できます。
--collapsed 引数を使用する必要があります。
jeprof /tmp/jemalloc_clickhouse.12345.0.heap.symbolized --collapsed > result.collapsedまたは、シンボル化されていないプロファイルの場合:
jeprof /path/to/clickhouse /tmp/jemalloc_clickhouse.12345.0.heap --collapsed > result.collapsedその後、コラプスされたスタックを可視化するために、さまざまなツールを利用できます。
最も一般的なのは FlameGraph で、flamegraph.pl というスクリプトが含まれています。
cat result.collapsed | /path/to/FlameGraph/flamegraph.pl --color=mem --title="Allocation Flame Graph" --width 2400 > result.svgもう 1 つの便利なツールとして、収集したスタックをよりインタラクティブに分析できる speedscope があります。
プロファイラの追加オプション
jemalloc では、プロファイラに関連するさまざまなオプションを利用できます。これらは MALLOC_CONF 環境変数を変更することで制御できます。
たとえば、割り当てサンプルの間隔は lg_prof_sample で制御できます。
heap profile を N バイトごとにダンプする場合は、lg_prof_interval を使用して有効にできます。
オプションの完全な一覧については、jemalloc のリファレンスページを確認することをお勧めします。
その他のリソース
ClickHouse/Keeper では、jemalloc 関連のメトリクスがさまざまな形で公開されています。
システムテーブル asynchronous_metrics
SELECT *
FROM system.asynchronous_metrics
WHERE metric LIKE '%jemalloc%'
FORMAT Verticalシステムテーブル jemalloc_bins
すべてのアリーナから集計した、異なるサイズクラス (ビン) ごとの jemalloc アロケータによるメモリ割り当てに関する情報を含みます。
システムテーブル jemalloc_stats (26.2+)
malloc_stats_print() の出力全体を、単一の文字列として返します。SYSTEM JEMALLOC STATS コマンドと同等です。
SELECT * FROM system.jemalloc_statsPrometheus
asynchronous_metrics の jemalloc 関連のすべてのメトリクスは、ClickHouse と Keeper の両方で Prometheus エンドポイント経由でも公開されています。
Keeper の jmst 4LW コマンド
Keeper は jmst 4LW コマンドをサポートしており、基本的なアロケータ統計情報を返します:
echo jmst | nc localhost 9181