アロケーションプロファイリング
ClickHouse はグローバルアロケータとして jemalloc を使用しています。jemalloc にはアロケーションのサンプリングおよびプロファイリング用のツールが付属しています。
ClickHouse と Keeper では、設定ファイル、クエリ設定、SYSTEM コマンド、および Keeper の four letter word (4LW) コマンドを使用してサンプリングを制御できます。結果を確認する方法はいくつかあります:
system.trace_logにJemallocSample型としてサンプルを収集し、クエリ単位で分析する。- 組み込みの jemalloc web UI (26.2+) を通じて、リアルタイムのメモリ統計を表示し、ヒーププロファイルを取得する。
- SQL から
system.jemalloc_profile_text(26.2+) を使用して現在のヒーププロファイルを直接クエリする。 - ヒーププロファイルをディスクにフラッシュし、
jeprofで分析する。
このガイドはバージョン 25.9 以降に適用されます。 それ以前のバージョンについては、25.9 より前のバージョン向けアロケーションプロファイリング を参照してください。
アロケーションのサンプリング
アロケーションのサンプリングおよびプロファイリングを行うには、jemalloc_enable_global_profiler 設定を有効にして ClickHouse/Keeper を起動します。
jemalloc はアロケーションをサンプリングし、その情報を内部に保持します。
jemalloc_enable_profiler 設定を使用することで、クエリ単位のサンプリングを有効にすることもできます。
ClickHouse はアロケーションが多いアプリケーションであるため、jemalloc のサンプリングによりパフォーマンス上のオーバーヘッドが発生する可能性があります。
system.trace_log に jemalloc サンプルを保存する
jemalloc サンプルを JemallocSample 型として system.trace_log に格納できます。
これをグローバルに有効化するには、jemalloc_collect_global_profile_samples_in_trace_log 設定を使用します。
ClickHouse はメモリ割り当てを多用するアプリケーションであるため、system.trace_log ですべてのサンプルを収集すると高負荷になる可能性があります。
jemalloc_collect_profile_samples_in_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 をフラッシュします。
そして、それに対してクエリを実行し、時間の経過に応じた累積メモリ使用量を取得します。
メモリ使用量が最大となった時刻を特定します:
その結果を使って、ピーク時にどの割り当てスタックが最も活発だったかを確認できます。
Jemalloc Web UI
このセクションはバージョン 26.2 以降に適用されます。
ClickHouse には、/jemalloc HTTP エンドポイントで jemalloc メモリ統計情報を表示するための組み込みの Web UI が用意されています。
この UI では、割り当て済みメモリ、アクティブメモリ、常駐メモリ、マップ済みメモリに加えて、アリーナごとおよび bin ごとの統計情報を含むメモリメトリクスを、リアルタイムにグラフで表示します。
また、グローバルおよびクエリ単位のヒーププロファイルを UI から直接取得することもできます。
アクセスするには、ブラウザで次の URL を開きます。
SQL からヒーププロファイルを取得する
このセクションはバージョン 26.2 以降に適用されます。
system.jemalloc_profile_text システムテーブルを使用すると、外部ツールを利用したり、事前にディスクへフラッシュしたりすることなく、現在の jemalloc ヒーププロファイルを SQL から直接取得して表示できます。
このテーブルは 1 つのカラムのみを持ちます:
| カラム | Type | Description |
|---|---|---|
line | String | シンボル化された jemalloc ヒーププロファイルの 1 行です。 |
ヒーププロファイルを事前にフラッシュする必要はなく、このテーブルに対して直接クエリを実行できます:
出力形式
出力形式は jemalloc_profile_text_output_format 設定によって制御され、次の3つの値を取ります。
raw— jemalloc によって生成される生のヒーププロファイル。symbolized— 関数シンボルを埋め込んだ jeprof 互換の形式。シンボルがすでに埋め込まれているため、ClickHouse バイナリを用意しなくてもjeprofで出力を解析できます。collapsed(デフォルト) — FlameGraph 互換の折り畳みスタック形式。1 行につき 1 つのスタックと、そのスタックのバイト数が含まれます。
例えば、生のプロファイルを取得するには次のようにします。
シンボル情報付きの出力を得るには:
追加設定
jemalloc_profile_text_symbolize_with_inline(Bool, デフォルト:true) — シンボル化の際にインラインフレームを含めるかどうかを指定します。無効にするとシンボル化は大幅に高速になりますが、インライン化された関数呼び出しがスタックに現れなくなるため精度が低下します。symbolizedおよびcollapsedフォーマットにのみ影響します。jemalloc_profile_text_collapsed_use_count(Bool, デフォルト:false) —collapsedフォーマットを使用する場合、バイト数ではなくアロケーション回数で集約します。
例: SQL からフレームグラフを生成する
デフォルトの出力形式は collapsed なので、その出力をそのまま FlameGraph にパイプできます:
バイト数ではなく割り当て回数に基づいたフレームグラフを生成するには、次のようにします:
ヒーププロファイルをディスクにフラッシュする
ヒーププロファイルを jeprof でオフライン解析するためにファイルとして保存する必要がある場合は、プロファイルをディスクにフラッシュできます。
デフォルトでは、ヒーププロファイル用ファイルは /tmp/jemalloc_clickhouse._pid_._seqnum_.heap に生成されます。ここで _pid_ は ClickHouse の PID、_seqnum_ は現在のヒーププロファイルに対応するグローバルなシーケンス番号です。
Keeper のデフォルトファイルは /tmp/jemalloc_keeper._pid_._seqnum_.heap で、同じルールに従います。
現在のプロファイルをフラッシュするには次を実行します。
- ClickHouse
- Keeper
フラッシュされたプロファイルの保存先パスが返されます。
MALLOC_CONF 環境変数に prof_prefix オプションを追加することで、別の保存場所を指定できます。
例えば、/data ディレクトリ内に、ファイル名のプレフィックスを my_current_profile としてプロファイルを生成したい場合は、次の環境変数を指定して ClickHouse/Keeper を実行します。
生成されるファイル名は、プレフィックスに PID とシーケンス番号を連結したものになります。
jeprof を使用したヒーププロファイルファイルの分析
ヒーププロファイルをディスクにフラッシュした後は、jemalloc のツールである jeprof を使用して分析できます。次のいずれかの方法でインストールできます。
- システムのパッケージマネージャーを使用する
- jemalloc リポジトリをクローンし、ルートディレクトリで
autogen.shを実行する。これにより、binディレクトリ内にjeprofスクリプトが作成されます
利用可能な出力形式が多数用意されています。利用可能なオプションの一覧は、jeprof --help を実行して確認してください。
シンボル情報付きヒーププロファイル
バージョン 26.1 以降では、SYSTEM JEMALLOC FLUSH PROFILE を使用してフラッシュを実行すると、ClickHouse は自動的にシンボル情報付きのヒーププロファイルを生成します。
シンボル情報付きプロファイル(拡張子は .symbolized)には関数シンボルが埋め込まれており、ClickHouse のバイナリを用意しなくても jeprof で分析できます。
たとえば、次のように実行すると:
ClickHouse は、シンボル化されたプロファイルへのパスを返します(例: /tmp/jemalloc_clickhouse.12345.0.heap.symbolized)。
その後、これを jeprof で直接解析できます。
バイナリは不要です: シンボル化されたプロファイル(.symbolized ファイル)を使用する場合、jeprof に ClickHouse バイナリのパスを指定する必要はありません。これにより、別のマシン上で、あるいはバイナリを更新した後でも、プロファイルをはるかに簡単に分析できるようになります。
古いシンボル化されていないヒーププロファイルがあり、引き続き ClickHouse バイナリにアクセスできる場合は、従来の方法を使用できます。
シンボル化されていないプロファイルの場合、jeprof はスタックトレースを生成するために addr2line を使用しますが、処理が非常に遅くなることがあります。
その場合は、このツールの代替実装をインストールすることを推奨します。
また、llvm-addr2line も同様に問題なく動作します(ただし、llvm-objdump は jeprof とは互換性がない点に注意してください)。
その後、次のように指定して使用します: jeprof --tools addr2line:/usr/bin/llvm-addr2line,nm:/usr/bin/llvm-nm,objdump:/usr/bin/objdump,c++filt:/usr/bin/llvm-cxxfilt
:::
2つのプロファイルを比較する際には、--base 引数を使用できます。
例
シンボル化されたプロファイルを使用する(推奨):
- 各プロシージャを 1 行に 1 つずつ記載したテキストファイルを生成します:
- コールグラフを含む PDF ファイルを生成する:
シンボル化されていないプロファイルを使用する場合(バイナリが必要):
- 各関数を 1 行ずつ記述したテキストファイルを生成します。
- コールグラフを含む PDF ファイルを生成する:
フレームグラフの生成
jeprof を使用すると、フレームグラフの作成に必要なコラプスされたスタック(collapsed stacks)を生成できます。
--collapsed 引数を使用する必要があります。
あるいは、シンボル情報のないプロファイルの場合:
その後は、コラプスされたスタックを可視化するために利用できるツールが多数あります。
最も広く使われているのは FlameGraph で、flamegraph.pl というスクリプトが含まれています。
もう 1 つ便利なツールとして speedscope があり、収集したスタックをよりインタラクティブに分析できます。
プロファイラ用の追加オプション
jemalloc にはプロファイラに関連する多くのオプションがあり、MALLOC_CONF 環境変数を変更することで制御できます。
例えば、メモリ割り当てサンプル間の間隔は lg_prof_sample で制御できます。
ヒーププロファイルを N バイトごとにダンプしたい場合は、lg_prof_interval を有効にします。
利用可能なオプションの完全な一覧については、jemalloc の リファレンスページ を参照してください。
その他のリソース
ClickHouse/Keeper は、jemalloc 関連のメトリクスをさまざまな方法で公開します。
これらのメトリクスは相互に同期されておらず、値がずれる可能性があることを認識しておくことが重要です。
システムテーブル asynchronous_metrics
システムテーブル jemalloc_bins
すべてのアリーナから集約された、さまざまなサイズクラス(bin)における jemalloc アロケータによるメモリ割り当てに関する情報を含みます。
システムテーブル jemalloc_stats (26.2+)
malloc_stats_print() の出力全体を単一の文字列として返します。SYSTEM JEMALLOC STATS コマンドと同等です。
Prometheus
asynchronous_metrics に含まれるすべての jemalloc 関連メトリクスは、ClickHouse と Keeper の両方で Prometheus エンドポイントからも公開されます。
Keeper における jmst 4LW コマンド
Keeper は jmst 4LW コマンドをサポートしており、基本的なアロケータ統計情報を返します。