关于后端:一文教会你如何利用火焰图快速定位内存泄漏

40次阅读

共计 3547 个字符,预计需要花费 9 分钟才能阅读完成。

从 greptimedb#1733 开始,GreptimeDB 应用 Jemalloc 作为默认的内存分配器,这不仅有助于晋升性能和升高内存碎片,也提供了便捷的内存剖析性能。在 记一次 Rust 内存透露排查之旅 | 经验总结篇 这篇文章中,咱们介绍了剖析 Rust 利用内存透露的几种罕用办法,而在本文中将具体介绍基于 Jemalloc 的排查伎俩。

当您在应用或者开发 GreptimeDB 的过程中,如果遇到内存使用量异样的问题,能够参照本篇文章疾速排查和定位可能存在的内存透露。

筹备工作

装置必要工具

装置 flamegraph.pl 脚本

curl -s https://raw.githubusercontent.com/brendangregg/FlameGraph/master/flamegraph.pl > ${HOME}/.local/bin/flamegraph.pl
chmod +x ${HOME}/.local/bin/flamegraph.pl
export PATH=$PATH:${HOME}/.local/bin

flamegraph.pl 是由 Brendan Gregg 编写的用于可视化热点代码调用栈的一个 Perl 脚本。Brendan Gregg 是一位致力于零碎性能优化的专家,在此感激他开发并开源了包含 flamegraph.pl 在内的诸多工具。

装置 jeprof 命令

# For Ubuntu
sudo apt install -y libjemalloc-dev

# For Fedora
sudo dnf install jemalloc-devel

对于其余操作系统,您能够通过 pkgs.org 来查找 jeprof 的依赖包。

启用 GreptimeDB 的内存剖析性能

GreptimeDB 的内存剖析性能是一个默认敞开的个性,您能够通过在编译 GreptimeDB 时关上 mem-prof feature 来启用此性能。

cargo build --release -F mem-prof

对于是否应该默认开启 mem-prof 个性,greptimedb#3166 正在进行探讨,您也能够留下您的认识。

启动 GreptimeDB 并启用 mem-prof 性能

为了启用内存剖析性能,在启动 GreptimeDB 过程时也须要设置环境变量 MALLOC_CONF

MALLOC_CONF=prof:true ./<path_to_greptime_binary> standalone start

您能够通过 curl 命令来查看内存剖析性能是否失常应用:

curl <greptimedb_ip>:4000/v1/prof/mem

如果内存剖析性能曾经启用,此命令会返回相似如下的响应:

heap_v2/524288
  t*: 125: 136218 [0: 0]
  t0: 59: 31005 [0: 0]
...

MAPPED_LIBRARIES:
55aa05c66000-55aa0697a000 r--p 00000000 103:02 40748099                  /home/lei/workspace/greptimedb/target/debug/greptime
55aa0697a000-55aa11e74000 r-xp 00d14000 103:02 40748099                  /home/lei/workspace/greptimedb/target/debug/greptime
...

否则如果返回 {"error":"Memory profiling is not enabled"} ,则阐明 MALLOC_CONF=prof:true 环境变量未正确设置。

对于 内存剖析 API 所返回的数据格式,请参考 HEAP PROFILE FORMAT – jemalloc.net。

开始您的内存探险!

通过 curl <greptimedb_ip>:4000/v1/prof/mem 命令,您能够疾速获取 GreptimeDB 所调配的内存详情;通过 jeprofflamegraph.pl 能够将内存应用详情可视化为火焰图:

# 获取内存调配详情
curl <greptimedb_ip>:4000/v1/prof/mem > mem.hprof

# 生成内存调配的火焰图
jeprof <path_to_greptime_binary> ./mem.hprof --collapse | flamegraph.pl > mem-prof.svg

执行完以上命令后将在当前目录生成文件名为 mem-prof.svg 的火焰图:

如何浏览火焰图

火焰图是由 Brendan Gregg 发明的一种可能对 CPU 开销和内存调配详情进行剖析的利器,其生成原理是,在每次采样内存调配事件时,记录触发此次内存调配的函数调用栈。在记录足够屡次后,将每次调配的调用栈合并,从而失去每个函数调用以及其所调用的函数所调配的内存大小。

  • 火焰图的最下方为函数栈的栈底,而最上方为栈顶;
  • 火焰图中每一个格子代表一个函数调用,格子下方为此函数的调用者(caller),格子上方为此函数所调用的子函数(callee);
  • 格子的宽度代表此函数及其子函数所有分配内存的总量。当咱们发现某些函数的格子较宽,阐明此函数调配的内存较多。如果某些函数分配内存较多然而其子函数调配却并不多(如下图,火焰图中存在较宽的栈顶,即 plateaus),阐明此函数本身可能存在大量调配操作;
  • 火焰图中每个格子的色彩是随机的;
  • 在浏览器中关上火焰图的 SVG 文件能够交互式地点击进入每个函数进行更加具体的剖析。

快 1 倍!减速火焰图的生成

Jemalloc 返回的堆内存详情蕴含了调用栈各个函数的地址,在生成火焰图时须要将地址翻译成文件名和行号,而这正是耗时最长的步骤。通常在 Linux 零碎下,这项工作是由 GNU Binutils 中的 addr2line 工具实现的。为了放慢火焰图生成的速度,咱们能够用 glimi-rs/addr2line 来替换 Binutils 的 addr2line 工具,从而能够取得至多 1 倍的速度晋升。

git clone https://github.com/gimli-rs/addr2line
cd addr2line
cargo build --release
sudo cp /usr/bin/addr2line /usr/bin/addr2line-bak
sudo cp target/release/examples/addr2line /usr/bin/addr2line 

通过内存调配差值来捕获内存透露

在常见的内存透露场景中,内存的使用量往往是迟缓增长的。因而咱们在内存增长的过程中,别离截取两个工夫点的内存应用状况,两者之差往往批示着可能呈现内存透露的中央。

咱们能够在初始工夫点采集一次内存作为基准:

curl -s <greptimedb_ip>:4000/v1/prof/mem > base.hprof

当内存迟缓增长,疑似呈现内存透露时,再一次采集内存:

curl -s <greptimedb_ip>:4000/v1/prof/mem > leak.hprof

而后以 base.hprof 作为基准剖析内存占用并生成火焰图:

jeprof <path_to_greptime_binary> --base ./base.hprof ./leak.hprof --collapse | flamegraph.pl > leak.svg

在应用 --base 参数指定基准生成的火焰图中,只会蕴含本次采集内存调配和基准之间的内存差值的分配情况,从而可能更加清晰地看到内存使用量的增长到底是由哪些函数调用产生的。

对于 Greptime 的小常识:

Greptime 格睿科技于 2022 年创建,目前正在欠缺和打造时序数据库 GreptimeDB,格睿云 GreptimeCloud 和可观测工具 GreptimeAI 这三款产品。

GreptimeDB 是一款用 Rust 语言编写的时序数据库,具备分布式、开源、云原生和兼容性强等特点,帮忙企业实时读写、解决和剖析时序数据的同时升高长期存储老本;GreptimeCloud 能够为用户提供全托管的 DBaaS 服务,可能与可观测性、物联网等畛域高度联合;GreptimeAI 为 LLM 量身打造,提供老本、性能和生成过程的全链路监控。

GreptimeCloud 和 GreptimeAI 已正式公测,欢送关注公众号或官网理解最新动静!

官网:https://greptime.cn/

GitHub: https://github.com/GreptimeTeam/greptimedb

文档:https://docs.greptime.cn/

Twitter: https://twitter.com/Greptime

Slack: https://greptime.com/slack

LinkedIn: https://www.linkedin.com/company/greptime/

正文完
 0