背景
Flink作业设置内存参数后发现不是自己预期的资源分配方式,比如分配了4G内存结果只用了2G,其余2G都是闲置的,导致Flink作业内存上限不够用,内存超用时TaskManager容器会被Yarn集群杀死。另外并行度与slot槽数在Flink on Yarn集群模式下如何设置才能资源利用最大化,在本文给出优化建议
Flink TM内存分配机制
内存分配区域说明
组成部分 |
描述 |
框架堆内存 Framework Heap Memory |
用于 Flink 框架的 JVM 堆内存(进阶配置)。 |
任务堆内存 Task Heap Memory |
用于 Flink 应用的算子及用户代码的 JVM 堆内存。 |
托管内存 Managed memory |
由 Flink 管理的用于排序、哈希表、缓存中间结果及 RocksDB State Backend 的本地内存。 |
框架堆外内存 Framework Off-heap Memory |
用于 Flink 框架的堆外内存(直接内存或本地内存)(进阶配置)。 |
任务堆外内存 Task Off-heap Memory |
用于 Flink 应用的算子及用户代码的堆外内存(直接内存或本地内存)。 |
网络内存 Network Memory |
用于任务之间数据传输的直接内存(例如网络传输缓冲)。该内存部分为基于 Flink 总内存的受限的等比内存部分。这块内存被用于分配网络缓冲 |
JVM Metaspace |
Flink JVM 进程的 Metaspace。 |
JVM overhead |
用于其他 JVM 开销的本地内存,例如栈空间、垃圾回收空间等。该内存部分为基于进程总内存的受限的等比内存部分。 |
内存分配案例
设置(进程总内存)
taskmanager.memory.process.size:4196m
设置托管内存分配比例
taskmanager.memory.managed.fraction:0.4 (默认)
taskmanager.memory.managed.fraction:0.2
自动分配区域 |
分配内存值0.4 |
分配内存值0.2 |
备注 |
Framework Heap Memory |
128MB |
128MB |
|
Task Heap Memory |
1.47G |
2.16G |
任务算子可用内存空间 (影响任务效率) |
Managed memory |
1.38G |
704MB |
状态缓存可用内存空间 (影响checkpoint效率) |
Framework Off-heap Memory |
128MB |
128MB |
|
Task Off-heap Memory |
0b |
0B |
|
Network Memory |
352MB |
352MB |
闲置内存空间 |
JVM Metaspace |
256MB |
256MB |
使用少量内存空间 |
JVM overhead |
420MB |
420MB |
闲置内存空间 |
申请、容器内存合计 |
4196MB |
4196MB |
|
设置(Flink总内存)
taskmanager.memory.flink.size:4G
自动分配区域 |
分配内存值0.4 |
分配内存值0.2 |
备注 |
Framework Heap Memory |
128MB |
128MB |
|
Task Heap Memory |
1.80G |
2.62G |
任务算子可用内存空间 (影响任务效率) |
Managed memory |
1.64G |
839MB |
状态缓存可用内存空间 (影响checkpoint效率) |
Framework Off-heap Memory |
128MB |
128MB |
|
Task Off-heap Memory |
0b |
0B |
|
Network Memory |
420MB |
420MB |
闲置内存空间 |
申请内存合计 |
4196MB |
4196MB |
|
JVM Metaspace |
256MB |
256MB |
使用少量内存空间 |
JVM overhead |
495MB |
495MB |
闲置内存空间 |
容器内存合计 |
4947MB |
4947MB |
metaspace、overhead单独分配内存,不计入到申请内存中,容器内存会比预期申请的内存要大 |
案例分析
1、在相同的托管内存分配比例情况下,跟taskmanager.memory.process.size比较,设置taskmanager.memory.flink.size能申请分配更多的任务算子可用内存空间,因为JVM Metaspace、JVM overhead这两块区域空间不计入内存分配池子,额外算一部分内存(根据这两个参数的比例因子)
2、不管设置process.size还是flink.size,Network Memory、JVM overhead这两块空间都是闲置的内存空间,基本不会使用到,所以作业并行度和slot槽数设置越多(yarn集群下1并行度对应一个TaskManager容器),闲置内存空间会越多
实践总结
1、尽量设置taskmanager.memory.flink.size参数,能得到更多任务可用内存和托管内存
2、taskmanager.memory.managed.fraction托管内存分配比例这个参数只有在使用rocksdb状态存储情况下需要考虑设置成0.1~0.2值,使用hashmap可以设置更低,因为从实践来看基本不会用到这部分内存空间,目的就是尽可能的提高Task Heap Memory这块区域的内存可用空间,实践经验这块区域内存可用空间越大,Flink作业的吞吐量越大,作业的稳定性越高
3、TaskManager容器一般设置个3~4个就够了,更多的是提高任务可用内存空间的上限,在总内存相同情况下容器越多效率不一定高,容器多带来的网络IO消耗也更多
4、对于 YARN,如果 yarn.nodemanager.pmem-check-enabled设为true(公司集群已关闭) , 则会在运行时定期检查容器内的进程是否超用内存。如果进程总内存用量超出配额,容器平台通常会直接发送最严格的 SIGKILL 信号(相当于 )来中止 TaskManager,此时不会有任何延期退出的机会,可能会造成作业崩溃重启、外部系统资源无法释放等严重后果,所以没关闭这个检测前,提高容器算子任务可用内存上限很重要