SYSTEM 命令以及 Keeper 中的 four letter word (4LW) 命令来控制采样。你可以通过以下几种方式查看结果:
- 将 samples 收集到
system.trace_log中,类型为JemallocSample,以便进行按查询分析。 - 通过内置的 jemalloc web UI 查看实时内存统计信息,并拉取堆内存剖析 (26.2+) 。
- 使用 SQL 通过
system.jemalloc_profile_text直接查询当前堆内存剖析 (26.2+) 。 - 使用 SQL 通过
system.jemalloc_sampled_allocations分析内存碎片 (26.9+) 。 - 将堆内存剖析刷新到 disk,并使用
jeprof进行分析。
本指南适用于 25.9+ 版本。
对于更早的版本,请参阅25.9 之前版本的内存分配剖析。
内存分配采样
要对内存分配进行采样和分析,请先启用jemalloc_enable_global_profiler 配置项,然后启动 ClickHouse/Keeper:
jemalloc 会对内存分配进行采样,并在内部存储相关信息。
你也可以使用 jemalloc_enable_profiler 设置,为每个查询启用采样。
在 system.trace_log 中存储 jemalloc 采样数据
你可以将 jemalloc 采样数据以 JemallocSample 类型存储在 system.trace_log 中。
如需全局启用,请使用 jemalloc_collect_global_profile_samples_in_trace_log 配置项:
jemalloc_collect_profile_samples_in_trace_log 设置为单个查询启用此功能。
示例:分析查询的内存使用情况
首先,在启用 jemalloc Profiler 的情况下运行查询,并将 samples 收集到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 及以上版本。
/jemalloc HTTP 端点提供了一个内置的 web UI,用于查看 jemalloc 内存统计信息。
它通过图表展示实时内存指标,包括 allocated、active、resident 和 mapped memory,以及按 arena 和 bin 划分的统计信息。
你还可以直接在 UI 中拉取全局和按查询划分的堆内存剖析。
- ClickHouse
- Keeper
从 SQL 获取堆内存剖析
本节适用于 26.2 及以上版本。
system.jemalloc_profile_text 系统表可让您直接通过 SQL 获取并查看当前的 jemalloc 堆内存剖析,无需先借助外部工具,也不必先将其落盘。
该表只有一列:
您可以直接查询该表——无需预先落盘堆内存剖析:
输出格式
输出格式由jemalloc_profile_text_output_format 设置控制,它支持三个值:
raw— jemalloc 生成的原始堆内存剖析。symbolized— 与 jeprof 兼容的格式,内嵌函数符号。由于符号已内嵌,jeprof无需 ClickHouse 可执行文件即可分析输出。collapsed(默认) — 与 FlameGraph 兼容的折叠栈格式,每行一个调用栈,并附带字节数。
其他设置
jemalloc_profile_text_symbolize_with_inline(Bool, default:true) — 符号化时是否包含内联窗口帧。禁用此项可显著加快符号化速度,但会损失精度,因为内联函数调用将不会出现在堆栈中。仅影响symbolized和collapsed格式。jemalloc_profile_text_collapsed_use_count(Bool, default:false) — 使用collapsed格式时,按分配次数而非字节数聚合。
示例:从 SQL 生成火焰图
由于默认输出格式为collapsed,因此可将输出直接通过管道传给 FlameGraph:
通过 SQL 分析内存碎片
本节适用于 26.9 及更高版本。
system.jemalloc_arena_bins显示每个 arena 中每个大小类浪费了多少内存。waste表示被 slab 持有但未被存活分配使用的字节数。purpose标记专用 arena (mergetree、jit、cache) ;它们在设计上就用于存放长期存活的数据,因此排查异常碎片时应使用purpose = ''将其过滤掉。system.jemalloc_bins提供的是跨 arena 汇总后的相同数据。system.jemalloc_sampled_allocations列出当前仍然存活的采样分配,每个 sample 一行:调用栈 (trace) 、已存活时长 (age_ns) 、大小与大小类,以及所属 arena。读取该表会触发一次新的堆内存剖析刷写。
- 只有启用了 profiler 的线程才会产生 sample (配置中的
jemalloc_enable_global_profiler或jemalloc_enable_profiler设置) 。 - 每一行大约代表
weight次真实分配,而小分配被采样到的概率很低。如果你关注的大小类没有 sample,可调整jemalloc_profiler_sampling_rate。 - 采样分配不存放在 slab 中,因此其本身不会增加
waste。它们只是告诉你哪些代码会在该大小类中进行分配。 - 每个存活的 sample 都会额外占用两个数据页 (在 64 KiB 数据页的构建中为 128 KiB) ,直到该分配被释放为止。禁用 profiler 只会停止产生新的 sample,但不会释放已有的 sample。
示例:生成碎片化火焰图
同一个查询还可以按各回溯 (backtrace) 中较旧分配 (allocation) 数量的比例,将每个大小类的浪费量分摊到这些回溯上,并以flamegraph.pl 所需的 collapsed 格式输出结果。存在浪费但没有足够旧的样本的大小类会被归入 [unattributed] 帧,因此火焰图的总量即为总浪费量。每个查询只应读取一次 system.jemalloc_sampled_allocations:每次读取都会刷写一份新的 profile,因此两个子查询看到的数据会不一致。
将堆内存剖析刷写到磁盘
如果你需要将堆内存剖析保存为文件,以便使用jeprof 进行离线分析,可以将其刷写到磁盘。
默认情况下,堆内存剖析文件会生成在 /tmp/jemalloc_clickhouse._pid_._seqnum_.heap,其中 _pid_ 是 ClickHouse 的 PID,_seqnum_ 是当前堆内存剖析的全局序列号。
对于 Keeper,默认文件为 /tmp/jemalloc_keeper._pid_._seqnum_.heap,规则相同。
要刷写当前 profile:
- ClickHouse
- Keeper
MALLOC_CONF 环境变量中附加 prof_prefix 选项来指定其他位置。
例如,如果你想在 /data 目录中生成 profile,并将文件名前缀设为 my_current_profile,可以使用以下环境变量运行 ClickHouse/Keeper:
使用 jeprof 分析堆内存剖析文件
将堆内存剖析写入磁盘后,可以使用 jemalloc 提供的工具 jeprof 进行分析。可通过多种方式安装:
- 使用系统的软件包管理器
- 克隆 jemalloc 仓库,并在根目录运行
autogen.sh。这样会在bin目录中生成jeprof脚本
jeprof --help 可查看完整的选项列表。
符号化的堆内存剖析
自 26.1+ 版本起,ClickHouse 会在你使用SYSTEM JEMALLOC FLUSH PROFILE 执行 flush 时自动生成符号化的堆内存剖析。
符号化的堆内存剖析 (带有 .symbolized 扩展名) 包含已嵌入的函数符号,因此可由 jeprof 直接分析,而无需 ClickHouse 可执行文件。
例如,当你运行:
/tmp/jemalloc_clickhouse.12345.0.heap.symbolized) 。
然后,您可以直接使用 jeprof 对其进行分析:
无需二进制文件:使用符号化的堆内存剖析 (
.symbolized 文件) 时,无需向 jeprof 提供 ClickHouse 二进制文件的路径。这样一来,无论是在不同机器上,还是在二进制文件更新之后,分析这些剖析文件都会容易得多。对于未符号化的 profile,或者,
jeprof 会使用 addr2line 生成 stacktrace,这个过程可能会非常慢。
如果遇到这种情况,建议安装该工具的另一种实现。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--base 参数:
示例
使用符号化的堆内存剖析 (推荐) :- 生成一个文本文件,每行一个过程:
- 生成包含调用图的 PDF 文件:
- 生成一个文本文件,每行写入一个函数:
- 生成带有调用图的 PDF 文件:
生成火焰图
jeprof 支持生成用于构建火焰图的折叠栈。
你需要使用 --collapsed 参数:
flamegraph.pl 的脚本:
Profiler 的其他选项
jemalloc 提供了许多与 Profiler 相关的选项,这些选项可通过修改 MALLOC_CONF 环境变量来控制。
例如,可使用 lg_prof_sample 控制分配样本之间的时间间隔。
如果你想每分配 N 字节就转储一次堆内存剖析,可以通过 lg_prof_interval 启用该功能。
建议查阅 jemalloc 的参考页,以获取完整的选项列表。
其他资源
ClickHouse/Keeper 通过多种方式公开与jemalloc 相关的指标。
系统表 asynchronous_metrics
系统表 jemalloc_bins
包含从所有 arena 汇总而来的、通过 jemalloc 分配器在不同大小类 (bins) 中的内存分配信息。
参考
系统表 jemalloc_stats (26.2+)
将 malloc_stats_print() 的完整输出作为单个字符串返回。等同于 SYSTEM JEMALLOC STATS 命令。
Prometheus
asynchronous_metrics 中所有与 jemalloc 相关的指标,也会通过 ClickHouse 和 Keeper 的 Prometheus 端点公开。
参考
Keeper 中的 jmst 4LW 命令
Keeper 支持 jmst 4LW 命令,用于返回基础分配器统计信息: