1、Flink内存模型(TaskManager)
从上面的内存模型图可以看出内存结构:
1) Flink使用了JVM Heap(堆内内存)和Off-Heap Memory(堆外内存);
2)JVM Heap(堆内内存)包含Framework Heap(框架内存)和Task Heap(Task堆内内存);
3)Off-Heap Memory(堆外内存)包含Managed Memory(管理内存)、Direct Memory(直接内存)和JVM特有内存(JVM Metaspace + JVM Overhead);
4)Direct Memory(直接内存)包含Framework Memory(框架堆外内存)、Task Off-Heap(Task堆外内存)、Network(网络缓冲内存);
5)JVM Metaspace(元空间)和JVM Overhead(JVM执行开销)在堆外内存中,不计入Flink内存(Total Flink Memory)中,但是包含在启动指令分配的内存中;JVM Metaspace(元空间)和JVM Overhead(JVM执行开销)属于JVM特有内存,由JVM本身占用;
2、内存大小
2.1 JVM特定内存
JVM本身使用的内存,包含JVM的Metaspace和Overhead
① JVM matespace:JVM元空间
taskmanager.memory.jvm-metaspace.size ,默认 256m
② JVM overhead:执行开销,JVM执行时自身所需要的内容,包括线程堆栈、IO、编译缓存等所使用的内存。
taskmanager.memory.jvm-overhead.fraction,默认 0.1
taskmanager.memory.jvm-overhead.min,默认 192m
taskmanager.memory.jvm-overhead.max,默认 1g
总进程内存*fraction,如果小于配置的min(或大于配置的max)大小,则使用min/max大小
2.2 框架内存
Flink框架,即TaskManager本身所占用的内存,不计入Slot的资源中
堆内:taskmanager.memory.framework.heap.size,默认 128m
堆外:taskmanager.memory.framework.off-heap.size,默认 128m
2.3 Task内存
Task执行用户代码时所使用的内存
堆内:taskmanager.memory.task.heap.size,默认 none,由Flink内存扣除其他部分的内存得到
堆外:taskmanager.memory.task.off-heap.size,默认 0,表示不使用堆外内存
2.4 网络内存
网络数据交换所使用的堆外内存大小,如网络数据交换缓冲区
堆外:taskmanager.memory.network.fraction,默认 0.1
taskmanager.memory.network.min,默认 64m
taskmanager.memory.network.max,默认 1g
Flink内存*fraction,如果小于配置的min(或大于配置的max)大小,则使用min/max大小
Flink内存 = 总进程内存 - JVM元空间 - JVM执行开销
2.5 托管内存
用于RocksDB State Backend 的本地内存和批的排序、哈希表、缓冲中间结果。
堆外:taskmanager.memory.managed.fraction,默认 0.4
taskmanager.memory.managed.size,默认 none
如果size没指定,则等于Flink内存*fraction
3、案例分析
基于yarn模型,一般参数指定的是总进程内存,taskmanager.memory.process.size
比如指定为4G,每一块内存得到大小如下
1)计算Flink内存
JVM元空间256mb,默认固定
JVM执行开销:4g*0.1=409.6m,在[192m,1g]之间,最终结果为409.6m
Flink内存 = 4g - 256m - 409.6m = 3430.4m
2)框架内存,堆内堆外都是128m
3)网络内存 = 3430.4m * 0.1 = 343.04m,在[64m,1g]之间,最终结果为343.04m
4)托管内存 = 3430.4m * 0.4 = 1372.16m
5)Task堆内内存 = Flink内存 - 框架堆内内存 - 框架堆外内存 - 网络内存 - 托管内存
所以,本例中Task堆内内存 = 3430.4m - 128m - 128m - 343.04m - 1372.14m = 1459.2m
进程内存给多大,需不需要调整,需要具体情况具体分析,在实际项目中,观察Metric中各部分内存使用率,小的调大,大的调小,找到一个平衡点。同时,内存分配需要留足余量。
4、CPU个数分配
4.1 槽数 :CPU个数 = 1:1
-Djobmanager.memory.process.size=1024m \
-Dtaskmanager.memory.process.size=1024m \
-Dtaskmanager.numberOfTaskSlots=1 \
-Dparallelism.default=5 \
在上面的指令中,每个taskmanager的槽数为1,多少个并行度就会有多少个槽,因此也就会有多少个taskmanager;每个taskmanager分配1G内存 + 1cpu。最终分配的资源为6G内存+6个CPU(5个taskmanager+1个jobmanager)。
4.2 槽位:CPU个数 != 1:1
-Djobmanager.memory.process.size=1024m \
-Dtaskmanager.memory.process.size=1024m \
-Dtaskmanager.numberOfTaskSlots=2 \
-Dparallelism.default=5 \
上面的指令,如果分配的资源和3.1相同,则符合预期;如果内存分配了6G,CPU分配了4个,和预期不符,则说明yarn的配置需要调整;
在hadoop的配置文件中,有一个配置文件 capacity-schedule.xml,其中有一个配置如下
其中,默认的资源计算器是 DefaultResourceCalculator 。这个计算器有一个问题,计算资源时,参照依据是以内存为主,CPU方面,为每个容器(taskmanager 或 jobmanager)分配一个最少数,即1个;如果出现上述不符合预期的情况,应该使用另一张资源计算器 DominantResourceCalculator ,这个计算器同时考虑内存和CPU的需求为程序申请资源。
调整后,将配置分发到集群每个节点,重启yarn,重新启动程序,再观察资源分配情况,是否符合预期。
4.3 强制指定每个taskmanager的CPU数
-Djobmanager.memory.process.size=1024m \
-Dtaskmanager.memory.process.size=1024m \
-Dtaskmanager.numberOfTaskSlots=2 \
-Dparallelism.default=5 \
-Dyarn.containers.vcores=3 \
上面这个指令,会为程序申请到 4G内存 + 10个CPU,其中3个taskmanager,每个taskmanager 1G内存+3个CPU,1个jobmanager 1G内存 + 1个CPU;
注意,这里指定的每个 taskmanager 的CPU个数,不能超过 yarn-site.xml 中配置的核心数的最大值,默认是8。
5、并行度设置
设置并行度的四种方式:配置文件:默认并行度(1)、提交参数、代码:env、代码:算子。
优先级为:配置文件:默认并行度(1) < 提交参数 < 代码:env < 代码:算子。