利用jemalloc解决flink的内存溢出问题

前言:

遇到一个Linux系统 glibc内存分配导致的OOM问题,根源是内存回收出现问题,导致碎片太多,内存无法回收,系统认为内存不够用了。
涉及到以下知识点:
1、Linux中典型的64M内存区域问题
2、glibc内存分配器ptmalloc2的底层原理
3、glibc的内存分配原理(Arean、Chunk、bins等)
4、malloc_trim对内存回收的影响

1、问题描述

前段时间做POC,在测试的过程中发现一个问题,使用Flink集群Session模式反复跑批处理任务时,集群某些节点TaskManger总是突然挂掉。
查看挂掉节点的系统日志发现原因是:操作系统内存被耗尽,触发了系统OOM,导致Flink TaskManager进程被操作系统杀掉了,下图:
图一

从图二可以看到,taskManager进程已经占了67%的内存40多G内存,继续跑任务还会继续增加
图二

2、配置

2.1 测试环境及配置

测试使用的版本如下所示:
Flink 1.14.3
Icberg 0.13.1
Hive 3.1.2
Hadoop 3.3.1
jdk1.8.0_181
FLink Standalone配置
jobmanager.rpc.address: 127.127.127.127
jobmanager.rpc.port: 6123
env.java.opts: “-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/bigdata/dump.hprof”
jobmanager.memory.process.size: 2000m – flink JM进程总内存
jobstore.expiration-time: 36000 – 已完成任务保留时间,每个任务会消耗50M内存
taskmanager.memory.process.size: 22000m – Flink TM进程总内存
taskmanager.numberOfTaskSlots: 22
parallelism.default: 100
taskmanager.network.sort-shuffle.min-parallelism: 1 – 默认使用sort-shuffle,flink 1.15之后默认就是1
taskmanager.network.blocking-shuffle.compression.enabled: true – 是否启用压缩
taskmanager.memory.framework.off-heap.size: 1000m
taskmanager.memory.framework.off-heap.batch-shuffle.size: 512m
execution.checkpointing.interval: 60000
execution.checkpointing.unaligned: true – 启用未对齐的检查点,这将大大减少背压下的检查点时间
execution.checkpointing.mode: AT_LEAST_ONCE – 配置数据处理次数,至少一次可以减少背压,加快处理速度
io.tmp.dirs: /home/testdir – 临时文件存储位置,批处理和流处理,要注意磁盘空间是否够用
execution.checkpointing.checkpoints-after-tasks-finish.enabled: true – 打开已完成job不影响checkpoint
可以看到,在配置中,此TaskManager分配的内存为22G,实际上通过TOP看到的结果已经达到了40+G。

4、定位过程

4.1 查看内存占用情况

经过初步定位发现,在调用icebergStreamWriter的时候内存会猛涨一下,任务跑完之后,这块多出来的内存并不会回收,怀疑是申请了堆外内存做缓存,用完之后未释放
首先通过阿里的Arthas看一下内存情况

curl -O https://arthas.aliyun.com/arthas-boot.jar

java -jar arthas-boot.jar

[INFO] arthas-boot version: 3.5.5
[INFO] Process 142388 already using port 3658
[INFO] Process 142388 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.

  • [1]: 142388 org.apache.flink.runtime.taskexecutor.TaskManagerRunner
    [2]: 2161 org.apache.ranger.authentication.UnixAuthenticationService
    [3]: 142577 org.apache.flink.table.client.SqlClient
    [4]: 170692 org.apache.hadoop.hdfs.server.datanode.DataNode
    [5]: 170900 org.apache.hadoop.yarn.server.nodemanager.NodeManager
    [6]: 73912 org.apache.flink.table.client.SqlClient
    [7]: 141982 org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint

然后输入1,Enter

然后输入dashboard即可看到当前内存情况
在这里插入图片描述

可以发现进程的堆内存只有6.3G,非堆也很小,加起来不到6.5G,那另外30多G内存被谁消耗了,查看JVM内存分配,如下所示

  • 堆(Heap):eden、metaspace、old 区域等
  • 线程栈(Thread Stack):每个线程栈预留 1M 的线程栈大小
  • 非堆(Non-heap):包括 code_cache、metaspace 等
  • 堆外内存:unsafe.allocateMemory 和 DirectByteBuffer申请的堆外内存
  • native (C/C++ 代码)申请的内存
  • 还有 JVM 运行本身需要的内存,比如 GC 等。

初步怀疑这块内存应该是被native内存或者堆外内存消耗掉了
堆外内存可以使用NMT(Native Memory Tracking (NMT) )工具进行查看
NMT必须先通过VM启动参数中打开,不过要注意的是&

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值