前言
最近笔者因为flink集群运行在kubernetes上,由于不可抗力导致pod重生,job需要restart,在没有开启checkpoint的情况下,作业只要重启就会频繁被os kill,这明显是堆外内存超用的现象。
heap memory和direct memory被jvm控制了,显然不会被os kill,而是OOM,可以被flink 捕捉而爆出异常的,被os kill只有托管给rocksdb的native memory了。
如何分析native memory的leak呢,就需要引入jemalloc。
什么是jemalloc
系统的物理内存是有限的,而对内存的需求是变化的, 程序的动态性越强,内存管理就越重要,选择合适的内存管理算法会带来明显的性能提升。
比如nginx, 它在每个连接accept后会malloc一块内存,作为整个连接生命周期内的内存池。 当HTTP请求到达的时候,又会malloc一块当前请求阶段的内存池, 因此对malloc的分配速度有一定的依赖关系。
内存管理可以分为三个层次,自底向上分别是:
- 操作系统内核的内存管理
- glibc层使用系统调用维护的内存管理算法
- 应用程序从glibc动态分配内存后,根据应用程序本身的程序特性进行优化, 比如使用引用计数std::shared_ptr,apache的内存池方式等等。
当然应用程序也可以直接使用系统调用从内核分配内存,自己根据程序特性来维护内存,但是会大大增加开发成本
glibc malloc的实现是ptmalloc2,其替代品tcmalloc 和 jemalloc。
tcmalloc
tcmalloc是Google开源的一个内存管理库, 作为glibc malloc的替代品。目前已经在chrome、safari等知名软件中运用。
根据官方测试报告,ptmalloc在一台2.8GHz的P4机器上(对于小对象)执行一次malloc及free大约需要300纳秒。而TCMalloc的版本同样的操作大约只需要50纳秒。
jemalloc
jemalloc是facebook推出的, 最早的时候是freebsd的libc malloc实现。 目前在firefox、facebook服务器各种组件中大量使用。
对应的git地址如下
https://github.com/jemalloc/jemalloc/blob/dev/INSTALL.md
jemalloc有一项功能,对应长时间运行的程序可以trace内存,见文档[6]。
如果想更加详细的了解这三者的性能和对比,可以参考文档[5]
环境
笔者的flink集群版本是1.10.1,运行在1.17的kubernetes上。
编译jemalloc
下载1
wget https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2
解压
1 |
|
开始编译
1 | ./configure --enable-prof --enable-stats --enable-debug --enable-fill |
一定要加上–enable-prof 才可以使用heap-prof的功能
1 | make |
对我们来说,需要的是
1 | bin |
将文件打入flink镜像中
1 | bin |
打入flink镜像1
ADD jemalloc /opt/jemalloc/
不知道怎么自己构建镜像的可以参考
配置jemalloc
如果flink的运行方式的native kubernetes,可以在构建集群的脚本添加
1 | -Dcontainerized.taskmanager.env.LD_PRELOAD: /opt/jemalloc/lib/libjemalloc.so.2 |
如果是on kubernetes的standalone,那么需要修改deployment
1 | env: |
配置解释:
LD_PRELOAD: 将内存分配从ptmalloc2改为libjemalloc.so.2
MALLOC_CONF: jemalloc的配置,prof_prefix是将生成的内存文件dump到指定文件。lg_prof_interval:30 是 2^30 byte(1G)生成一个文件,具体参数可以参考
https://github.com/jemalloc/jemalloc/blob/dev/INSTALL.md
进入容器补充工具
可以到/opt/state/tmp/下看到很多jeprof.out开头的heap文件
由于flink的容器是最简化模式,会缺少很多工具,想要直接使用jeprof是会缺少很多的,需要补充下载
先将源改为国内的源
在容器内运行
1 | mv /etc/apt/sources.list /etc/apt/sources.list.bak |
安装对应的工具1
apt-get install -y binutils graphviz ghostscript
分析内存
1 | /opt/jemalloc/bin/jeprof --show_bytes `which java` /opt/state/tmp/jeprof.out.301.808.i808.heap |
1 |
|
可以导出成pdf或者svg
1 | Output type: |
1 | /opt/jemalloc/bin/jeprof --show_bytes -svg `which java` /opt/state/tmp/jeprof.out.301.1009.i1009.heap > 105.svg |
Refernce
[2]jemalloc初体验
[3]Using jemalloc to get to the bottom of a memory leak
[4]Debugging Java Native Memory Leaks