《Flink 内存管理》系列(已完结),共包含以下 4 篇文章:
- Flink 内存管理(一):设置 Flink 进程内存
- Flink 内存管理(二):JobManager 内存分配(含实际计算案例)
- Flink 内存管理(三):TaskManager 内存分配(理论篇)
- Flink 内存管理(四):TaskManager 内存分配(实战篇)
😊 如果您觉得这篇文章有用 ✔️ 的话,请给博主一个一键三连 🚀🚀🚀 吧 (点赞 🧡、关注 💛、收藏 💚)!!!您的支持 💖💖💖 将激励 🔥 博主输出更多优质内容!!!
Flink 内存管理(三):TaskManager 内存分配
TaskManager 在 Flink 中运行用户代码。根据需要配置内存使用量可大大减少 Flink 的资源占用并提高任务稳定性。与 JobManager 进程的内存模型相比,TaskManager 内存组件具有类似但更复杂的结构。
1.配置 Total Memory
Flink JVM 进程的总内存(Total Process Memory
)由 Flink 应用程序(Total Flink Memory
,Flink 总内存)和 JVM 运行进程所消耗的内存组成。Flink 总内存( Total Flink Memory
)包括 JVM Heap
、Managed Memory
(托管内存,由 Flink 管理)和其他 Direct Memory
(或 Native Memory
)的使用量。
- 如果您在本地运行 Flink(例如从集成开发环境运行)而不创建集群,那么只有内存配置选项的一个子集与之相关,请参阅 “本地内存配置”。
- 否则,为 TaskManager 设置内存的最简单方法就是 配置总内存。这里 将详细介绍一种更精细的方法。
- 其余内存组件将根据默认值或附加配置选项自动调整。有关其他内存组件的更多详情,请参阅后续章节。
2.配置 Heap and Managed Memory
正如之前在总内存描述中提到的,在 Flink 中设置内存的另一种方法是明确指定 Task Heap Memory
和 Managed Memory
。这样,Flink 的任务和托管内存就能更好地控制可用的 JVM 堆。
其余的内存组件将自动调整。
如果已明确配置了任务 Task Heap Memory
和 Managed Memory
,建议既不要设置进程总内存(Total Process Memory
),也不要设置 Flink 总内存(Total Flink Memory
)。否则,很容易导致内存配置冲突。
2.1 Task (Operator) Heap Memory
如果要保证用户代码有一定量的 JVM 堆可用,可以显式设置 Task Heap Memory
(taskmanager.memory.task.heap.size
)。它将被添加到 JVM 堆大小中,并专门用于运行用户代码的 Flink Operator。
2.2 Managed Memory
托管内存由 Flink 管理,并作为本地内存(堆外)分配。以下工作负载使用托管内存:
- 流式工作可将其用于 RocksDB 状态后端。
- 流式和批处理作业都可以用它来进行排序、哈希表、缓存中间结果。
- 流式和批处理作业都可以用它来执行 Python 进程中的用户自定义函数。
托管内存的大小可以:
- 可通过
taskmanager.memory.managed.size
进行显式配置。 - 或通过
taskmanager.memory.managed.fraction
计算为 Flink 总内存(Total Flink Memory
)的一部分。
如果同时设置了大小和比例,则大小优先于比例。如果既没有明确配置大小,也没有配置比例,则将使用默认比例。
如果作业包含多种类型的托管内存消费者,还可以控制托管内存在这些类型之间的共享方式。配置选项 taskmanager.memory.managed.consumer-weights
允许你为每种类型设置一个权重,Flink 将根据该权重按比例预留托管内存。有效的消费者类型有:
OPERATOR
:用于内置算法。TATE_BACKEND
:用于流式传输中的 RocksDB 状态后端。PYTHON
:用于 Python 进程。
例如,如果一个流作业同时使用了 RocksDB 状态后端和 Python UDF,且消费者权重配置为 STATE_BACKEND:70,PYTHON:30
,那么 Flink 将为该作业预留
70
%
70\%
70% 的内存。
对于每种类型,只有当作业包含该类型的托管内存消费者时,Flink 才会为其保留托管内存。例如,如果流作业使用堆状态后端和 Python UDF,且消费者权重配置为 STATE_BACKEND:70,PYTHON:30
,Flink 将为 Python 进程使用所有托管内存,因为堆状态后端不使用托管内存。
🚀 Flink 不会为消费者权重中未包含的消费者类型预留托管内存。如果作业确实需要缺少的类型,就会导致内存分配失败。默认情况下,所有消费者类型都包含在内。只有在显式配置 / 改写权重时才会发生这种情况。
3.配置 Off-Heap Memory(Direct or Native)
- 用户代码分配的堆外内存应计入任务堆外内存(
taskmanager.memory.task.off-heap.size
)。 - 你也可以调整框架的堆外内存(
Framework Off-Heap Memory
)。只有在确定 Flink 框架需要更多内存时,才可更改该值。 - Flink 将框架堆外内存(
Framework Off-Heap Memory
)和任务堆外内存(Task Off-Heap Memory
)纳入 JVM 的直接内存(Direct Memory
)限制。 - 虽然本地非直接内存(
Native Non-Direct Memory
)的使用可以作为框架堆外内存或任务堆外内存的一部分,但在这种情况下会导致更高的 JVM 直接内存限制。 - 网络内存(
Network Memory
)也是 JVM 直接内存的一部分,但它由 Flink 管理,并保证永远不会超过其配置大小。因此,调整网络内存大小对这种情况没有帮助。
4.详细内存模型
下表列出了上面描述的所有内存组件,并引用了影响各组件大小的 Flink 配置选项:
组件 |
|
|
---|---|---|
Framework Heap Memory | taskmanager.memory.framework.heap.size (默认
128
M
128M
128M) | 专用于运行 Flink 框架,通常不用修改该值,它可能与特定的部署环境或作业结构有关,例如高并行度 |
Task Heap Memory | taskmanager.memory.task.heap.size | 专用于用户提交作业划分的 Tasks |
Managed Memory | taskmanager.memory.managed.size taskmanager.memory.managed.fraction (默认
0.4
0.4
0.4) | 这是一块被 Flink 管理的堆外内存,属于 Native Memory,用于批处理作业的排序,Hash 运算,缓存中间结果,以及 RocksDB 状态后端的元数据 |
Framework Off-Heap Memory | taskmanager.memory.framework.off-heap.size (默认
128
M
128M
128M) | 专用于运行 Flink 框架,通常不用修改该值,它可能与特定的部署环境或作业结构有关,例如高并行度 |
Task Off-Heap Memory | taskmanager.memory.task.off-heap.size (默认
0
B
y
t
e
0Byte
0Byte) | 专用于用户提交作业划分的 Tasks,不受 GC 的影响 |
Network Memory | taskmanager.memory.network.min (默认
64
M
B
64MB
64MB)taskmanager.memory.network.max (默认
1
G
B
1GB
1GB)taskmanager.memory.network.fraction (默认
0.1
0.1
0.1) | 为 Task 之间的数据交换预留的内存,比如说网络缓冲区,默认是 Total Flink Size 的 0.1,通常不需要去调整这个值 |
JVM Metaspace | taskmanager.memory.jvm-metaspace.size (默认
256
M
256M
256M) | JM 的元空间大小,有默认值 256 M 256M 256M, 属于 Native Memory |
JVM Overhead | taskmanager.memory.jvm-overhead.min (
192
M
B
192MB
192MB)taskmanager.memory.jvm-overhead.max (
1
G
B
1GB
1GB)taskmanager.memory.jvm-overhead.fraction (
0.1
0.1
0.1) | 为 Thread Stacks,Code Cache,Garbage Collection Space 预留的 Native Memory,有默认的 faction of total process size ,但是必须在其 min & max 之间 |
正如你所看到的,某些内存组件的大小可以通过相应选项进行简单设置。其他组件则可以使用多个选项进行调整。
5.Framework Memory
在没有充分理由的情况下,不应更改框架堆内存(Framework Heap Memory
)和框架堆外内存(Framework Off-Heap Memory
)。只有在确定 Flink 的某些内部数据结构或操作需要更多内存时,才可以调整它们。这可能与特定的部署环境或作业结构(如高并行性)有关。此外,在某些设置中,Flink 的依赖项(如 Hadoop)可能会消耗更多的直接或本地内存。
Flink 目前既没有隔离 Framework Heap Memory
和 Task Heap Memory
,也没有隔离 Framework Off-Heap Memory
和 Task Off-Heap Memory
。框架内存和任务内存的分离可用于未来版本的进一步优化。
6.Local Execution
如果您在机器上以单个 Java 程序的形式本地启动 Flink,而不创建集群(例如从集成开发环境),那么除了以下组件外,所有组件都将被忽略:
内存组件 |
| 本地执行的默认值 |
---|---|---|
Task Heap | taskmanager.memory.task.heap.size | 无限 |
Task Off-Heap | taskmanager.memory.task.off-heap.size | 无限 |
Managed Memory | taskmanager.memory.managed.size | 128 M B 128MB 128MB |
Network Memory | taskmanager.memory.network.min taskmanager.memory.network.max | 64 M B 64MB 64MB |
上面列出的所有组件均可配置为本地执行,但并非必须。如果没有配置,它们将被设置为默认值。任务堆内存(Task Heap
)和任务堆外内存(Task Off-Heap
)被视为无限大(Long.MAX_VALUE
字节),托管内存(Managed Memory
)的默认值为 128MB,仅适用于本地执行模式。
在这种情况下,任务堆大小与实际堆大小没有任何关系。它可能与未来版本的优化有关。Flink 无法控制已启动的本地进程的实际 JVM 堆大小,这取决于您如何启动进程。如果要控制 JVM 堆大小,必须明确传递相应的 JVM 参数,例如 -Xmx
、-Xms
。