Allocation profiling
ClickHouse 使用 jemalloc 作为全局分配器。jemalloc 自带用于分配采样和分析的工具。
ClickHouse 和 Keeper 允许你通过配置、查询设置、SYSTEM 命令以及 Keeper 中的 four letter word (4LW) 命令来控制采样。可以通过多种方式检查结果:
- 将样本收集到
system.trace_log中的JemallocSample类型,以进行按查询分析。 - 通过内置的 jemalloc web UI(26.2+)查看实时内存统计信息并获取堆内存分析概要(heap profile)。
- 使用 SQL 直接查询当前堆内存分析概要:
system.jemalloc_profile_text(26.2+)。 - 将堆内存分析概要写入磁盘,并使用
jeprof进行分析。
本指南适用于 25.9 及以上版本。 对于更早的版本,请查看25.9 之前版本的分配分析说明。
采样内存分配
如需对内存分配进行采样和分析,请在启动 ClickHouse/Keeper 时启用配置项 jemalloc_enable_global_profiler:
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 profiler 运行查询,并将采样数据收集到 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 提供了一个内置的 Web UI,可通过 /jemalloc HTTP 端点查看 jemalloc 内存统计信息。
界面使用图表展示实时内存指标,包括已分配、活动、常驻和映射内存,以及按 arena 和按 bin 的统计信息。
还可以直接在该 UI 中获取全局和按查询的堆内存剖析(heap profile)。
要访问它,请在浏览器中打开:
通过 SQL 获取堆内存分析配置文件
本节适用于 26.2+ 版本。
system.jemalloc_profile_text 系统表允许你直接通过 SQL 获取并查看当前的 jemalloc 堆内存分析配置文件,而无需使用外部工具或先写入磁盘。
该表仅包含一列:
| Column | Type | Description |
|---|---|---|
line | String | 来自已符号化 jemalloc 堆内存分析配置文件的一行内容。 |
你可以直接对该表执行查询——无需事先将堆内存分析配置文件写入磁盘:
输出格式
输出格式由 jemalloc_profile_text_output_format 设置控制,它支持三个取值:
raw— 由 jemalloc 生成的原始 heap profile。symbolized— 含有嵌入函数符号的、与 jeprof 兼容的格式。由于符号已嵌入,jeprof可以在不需要 ClickHouse 可执行文件的情况下对输出进行分析。collapsed(默认)— 与 FlameGraph 兼容的折叠调用栈格式,每行一个调用栈并附带字节数。
例如,要获取原始 heap profile:
要获取符号化后的输出:
其他设置
jemalloc_profile_text_symbolize_with_inline(Bool,默认值:true)—— 在符号化时是否包含内联帧。禁用该选项可以显著加快符号化速度,但会降低精度,因为内联函数调用将不会出现在调用栈中。仅影响symbolized和collapsed格式。jemalloc_profile_text_collapsed_use_count(Bool,默认值:false)—— 使用collapsed格式时,按分配次数而不是字节数进行聚合。
示例:从 SQL 生成 flame graph(火焰图)
由于默认输出格式为 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
在比较两个分析概要时,可以使用 --base 参数:
示例
使用带符号信息的 profile(推荐):
- 生成一个文本文件,每个过程一行:
- 生成包含调用关系图的 PDF 文件:
使用未符号化的 profile(需要二进制文件):
- 生成一个文本文件,每个过程名称占一行:
- 生成带有调用关系图的 PDF 文件:
生成火焰图
jeprof 可以生成用于构建火焰图的折叠后调用栈。
需要使用 --collapsed 参数:
或者使用未符号化的剖析概要:
接下来,你可以使用许多不同的工具来可视化折叠后的调用栈。
最常用的是 FlameGraph,其中包含一个名为 flamegraph.pl 的脚本:
另一个有用的工具是 speedscope,它使你能够以更直观、交互的方式分析收集到的调用栈。
分析器的其他选项
jemalloc 提供了许多与分析器相关的选项。可以通过设置 MALLOC_CONF 环境变量来进行配置。
例如,可以使用 lg_prof_sample 控制分配采样之间的间隔。
如果你希望每分配 N 字节就导出一次堆分析概要,可以通过 lg_prof_interval 启用该功能。
建议查看 jemalloc 的参考页面以获取完整的选项列表。
其他资源
ClickHouse/Keeper 通过多种方式暴露与 jemalloc 相关的指标。
需要注意的是,这些指标之间并不同步,数值可能会出现偏移。
系统表 asynchronous_metrics
系统表 jemalloc_bins
包含通过 jemalloc 分配器在不同大小类(bins)中的内存分配情况,这些信息从所有 arena 聚合而来。
系统表 jemalloc_stats(26.2+)
以单个字符串形式返回 malloc_stats_print() 的完整输出。等价于 SYSTEM JEMALLOC STATS 命令。
Prometheus
来自 asynchronous_metrics 的所有与 jemalloc 相关的指标,也会通过 ClickHouse 和 Keeper 中的 Prometheus 端点对外暴露。
Keeper 中的 jmst 4LW 命令
Keeper 支持 jmst 4LW 命令,它会返回基础分配器统计信息: