Flink内存管理与调优

配置flink进程的内存

配置总内存

Flink JVM 进程的*进程总内存(Total Process Memory)*包含了由 Flink 应用使用的内存(Flink 总内存)以及由运行 Flink 的 JVM 使用的内存。 Flink 总内存(Total Flink Memory)包括 JVM 堆内存(Heap Memory)堆外内存(Off-Heap Memory)。 其中堆外内存包括直接内存(Direct Memory)本地内存(Native Memory)
在这里插入图片描述

配置 Flink 进程内存最简单的方法是指定以下两个配置项中的任意一个:

配置项TaskManager 配置参数JobManager 配置参数
Flink总内存taskmamager.memory.flink.sizejobmanager.memory.flink.size
进程总内存taskmanager.memory.process.sizejobmanager.memory.process.size

flink有三种部署方式,一种为本地模式,一种为standalone模式,还有一种为yarn或者mesos模式,这三种模式中,用户必须要选择一种进行配置(本地模式除外),否则flink将无法启动,这意味着,用户需要从以下的无默认值的配置参数中选择一个给出明确的配置

TaskManager:JobManager
taskmanager.memory.flink.sizejobmanager.memory.flink.size
taskmanager.memory.process.sizejobmanager.memory.process.size
taskmanager.memory.task.heap.size

taskmanager.memory.task.managed.size
jobmanager.memory.heap.size

不建议同时设置进程总内存Flink 总内存。 这可能会造成内存配置冲突,从而导致部署失败。 额外配置其他内存部分时,同样需要注意可能产生的配置冲突

JVM参数

Flink 进程启动时,会根据配置的和自动推导出的各内存部分大小,显式地设置以下 JVM 参数:

JVM参数TaskManager取值JobManager取值
-Xmx-Xms框架堆内存+任务堆内存JVM堆内存
-XX:MaxDirectMemorySize
(TaskManager 始终设置,JobManager 见注释)
框架堆外内存 + 任务堆外内存 + 网络内存堆外内存
-XX:MaxMetaspaceSizeJVM MetaspaceJVM Metaspace
受限的等比内存部分

本节介绍下列内存部分的配置方法,它们都可以通过指定在总内存中所占比例的方式进行配置,同时受限于相应的的最大/最小值范围。

  • JVM 开销:可以配置占用进程总内存的固定比例
  • 网络内存:可以配置占用 Flink 总内存的固定比例(仅针对 TaskManager)

相关内存部分的配置方法,请同时参考

TaskManagerJobManager 的详细内存模型。

这些内存部分的大小必须在相应的最大值、最小值范围内,否则 Flink 将无法启动。 最大值、最小值具有默认值,也可以通过相应的配置参数进行设置。 例如,如果仅配置下列参数:

  • 进程总内存 = 1000Mb
  • JVM 开销最小值 = 64Mb
  • JVM 开销最大值 = 128Mb
  • JVM 开销占比 = 0.1

那么 JVM 开销的实际大小将会是 1000Mb x 0.1 = 100Mb,在 64-128Mb 的范围内。

如果将最大值、最小值设置成相同大小,那相当于明确指定了该内存部分的大小。

如果没有明确指定内存部分的大小,Flink 会根据总内存和占比计算出该内存部分的大小。 计算得到的内存大小将受限于相应的最大值、最小值范围。 例如,如果仅配置下列参数:

  • 进程总内存 = 1000Mb
  • JVM 开销最小值 = 128Mb
  • JVM 开销最大值 = 256Mb
  • JVM 开销占比 = 0.1

那么 JVM 开销的实际大小将会是 128Mb,因为根据总内存和占比计算得到的内存大小 100Mb 小于最小值。

如果配置了总内存和其他内存部分的大小,那么 Flink 也有可能会忽略给定的占比。 这种情况下,受限的等比内存部分的实际大小是总内存减去其他所有内存部分后剩余的部分。 这样推导得出的内存大小必须符合最大值、最小值范围,否则 Flink 将无法启动。 例如,如果仅配置下列参数:

  • 进程总内存 = 1000Mb
  • 任务堆内存 = 100Mb(或 JobManager 的 JVM 堆内存
  • JVM 开销最小值 = 64Mb
  • JVM 开销最大值 = 256Mb
  • JVM 开销占比 = 0.1

进程总内存中所有其他内存部分均有默认大小,包括 TaskManager 的托管内存默认占比或 JobManager 的默认堆外内存。 因此,JVM 开销的实际大小不是根据占比算出的大小(1000Mb x 0.1 = 100Mb),而是进程总内存中剩余的部分。 这个剩余部分的大小必须在 64-256Mb 的范围内,否则将会启动失败。

配置TaskManager内存

Flink 的 TaskManager 负责执行用户代码。 根据实际需求为 TaskManager 配置内存将有助于减少 Flink 的资源占用,增强作业运行的稳定性。

本篇内存配置文档仅针对 TaskManager! 与 JobManager相比,TaskManager 具有相似但更加复杂的内存模型。

配置总内存

Flink JVM 进程的*进程总内存(Total Process Memory)*包含了由 Flink 应用使用的内存(Flink 总内存)以及由运行 Flink 的 JVM 使用的内存。 其中,*Flink 总内存(Total Flink Memory)*包括 JVM 堆内存(Heap Memory)、*托管内存(Managed Memory)*以及其他直接内存(Direct Memory)或本地内存(Native Memory)。
在这里插入图片描述

如果你是在本地运行 Flink(例如在 IDE 中)而非创建一个集群,那么本文介绍的配置并非所有都是适用的,详情请参考本地执行

其他情况下,配置 Flink 内存最简单的方法就是配置总内存。 此外,Flink 也支持更细粒度的内存配置,比如说配置堆内存和托管内存

Flink 会根据默认值或其他配置参数自动调整剩余内存部分的大小。 接下来的章节将介绍关于各内存部分的更多细节。

配置堆内存和托管内存

如配置总内存中所述,另一种配置 Flink 内存的方式是同时设置任务堆内存托管内存, 通过这种方式,用户可以更好地掌控用于 Flink 任务的 JVM 堆内存及 Flink 的托管内存的大小。

Flink 会根据默认值或其他配置参数自动调整剩余内存部分的大小。关于各内存部分的更多细节,请参考后续的内存详解。

注意: 如果已经明确设置了任务堆内存和托管内存,建议不要再设置进程总内存Flink 总内存,否则可能会造成内存配置冲突。

任务(算子)堆内存

如果希望确保指定大小的 JVM 堆内存给用户代码使用,可以明确指定任务堆内存(taskmanager.memory.task.heap.size )指定的内存将被包含在总的 JVM 堆空间中,专门用于 Flink 算子及用户代码的执行。

托管内存

托管内存是由 Flink 负责分配和管理的本地(堆外)内存。 以下场景需要使用托管内存

  • 流处理作业中用于 RocksDB State Backend。
  • 批处理作业中用于排序、哈希表及缓存中间结果。
  • 流处理和批处理作业中用于[在 Python 进程中执行用户自定义函数]。

可以通过以下两种范式指定托管内存的大小:

  • 通过 taskmanager.memory.managed.size 明确指定其大小。
  • 通过 taskmanager.memory.managed.fraction 指定在Flink 总内存中的占比。

当同时指定二者时,会优先采用指定的大小(Size)。 若二者均未指定,会根据默认占比进行计算。

请同时参考[如何配置 State Backend 内存](#state backend 内存)以及如何配置批处理作业内存

消费者权重

对于包含不同种类的托管内存消费者的作业,可以进一步控制托管内存如何在消费者之间分配。 通过 taskmanager.memory.managed.consumer-weights 可以为每一种类型的消费者指定一个权重,Flink 会按照权重的比例进行内存分配。 目前支持的消费者类型包括:

  • DATAPROC:用于流处理中的 RocksDB State Backend 和批处理中的内置算法。
  • PYTHON:用户 Python 进程。

例如,一个流处理作业同时使用到了 RocksDB State Backend 和 Python UDF,消费者权重设置为 DATAPROC:70,PYTHON:30,那么 Flink 会将 70% 的托管内存用于 RocksDB State Backend,30% 留给 Python 进程。

只有作业中包含某种类型的消费者时,Flink 才会为该类型分配托管内存。 例如,一个流处理作业使用 Heap State Backend 和 Python UDF,消费者权重设置为 DATAPROC:70,PYTHON:30,那么 Flink 会将全部托管内存用于 Python 进程,因为 Heap State Backend 不使用托管内存。

提示 对于未出现在消费者权重中的类型,Flink 将不会为其分配托管内存。 如果缺失的类型是作业运行所必须的,则会引发内存分配失败。 默认情况下,消费者权重中包含了所有可能的消费者类型。 上述问题仅可能出现在用户显式地配置了消费者权重的情况下。

配置堆外内存(直接内存或本地内存)

你也可以调整框架堆外内存(Framework Off-heap Memory)。 这是一个进阶配置,建议仅在确定 Flink 框架需要更多的内存时调整该配置。

Flink 将框架堆外内存任务堆外内存都计算在 JVM 的直接内存限制中,请参考 JVM 参数

提示 本地内存(非直接内存)也可以被归在框架堆外内存任务堆外内存中,在这种情况下 JVM 的直接内存限制可能会高于实际需求。

提示 网络内存(Network Memory)同样被计算在 JVM 直接内存中。 Flink 会负责管理网络内存,保证其实际用量不会超过配置大小。 因此,调整网络内存的大小不会对其他堆外内存有实质上的影响。

内存详解

在这里插入图片描述

TaskManager内存也包括堆内存和堆外内存

下表中列出了 Flink TaskManager 内存模型的所有组成部分,以及影响其大小的相关配置参数。

组成部分配置参数描述
框架堆内存(Framework Heap Memory)taskmanager.memory.framework.heap.size用于flink框架的JVM堆内存
任务堆内存(Task Heap Memory)taskmanager.memory.task.heap.size用于flink应用的算子和用户代码的JVM堆内存
托管内存(Managed Memory)taskmanager.memory.managed.size
taskmanager.memory.managed.fraction
由flink管理的用于排序、哈希表、缓存中间结果及Rocks DB State Backend的本地内存
框架堆外内存(Framework Off-Heap Memory)taskmanager.memory.framework.off-heap.size用于flink框架的堆外内存
任务堆外内存(Task Off-Heap Memory)taskmanager.memory.task.off-heap.size用于flink应用的算子及用户代码的堆外内存
网络内存(Network Memory)taskmanager.memory.network.min
taskmanager.memory.network.max
taskmanager.memory.network.fraction
用于任务之间数据传输的直接内存(例如网络传输缓冲),该内存为基于flink总内存的受限等比内存
JVM Metaspacetaskmanager.memory.jvm-metaspace.sizeFlink JVM进程的Metaspace
JVM开销taskmanager.memory.jvm-overhead.min
taskmanager.memory.jvm-overhead.max
taskmanager.memory.jvm-overhead.fraction
用于其他JVM开销的本地内存,例如栈空间、垃圾回收空间

我们可以看到,有些内存部分的大小可以直接通过一个配置参数进行设置,有些则需要根据多个参数进行调整。

框架内存

通常情况下,不建议对框架堆内存框架堆外内存进行调整。 除非你非常肯定 Flink 的内部数据结构及操作需要更多的内存。 这可能与具体的部署环境及作业结构有关,例如非常高的并发度。 此外,Flink 的部分依赖(例如 Hadoop)在某些特定的情况下也可能会需要更多的直接内存或本地内存。

提示 不管是堆内存还是堆外内存,Flink 中的框架内存和任务内存之间目前是没有隔离的。 对框架和任务内存的区分,主要是为了在后续版本中做进一步优化。

本地执行

配置JobManager内存

配置总内存

配置 JobManager 内存最简单的方法就是进程的配置总内存, 本地模式下不需要为 JobManager 进行内存配置,配置参数将不会生效。

详细配置

在这里插入图片描述

如上图所示,下表中列出了 Flink JobManager 内存模型的所有组成部分,以及影响其大小的相关配置参数。

组成部分配置参数描述
JVM堆内存jobmanager.memory.heap.sizeJobManager JVM堆内存
堆外内存jobmanager.memory.off-heap.sizeJobManager JVM堆外内存
JVM Metaspacejobmanager.memory.jvm-metaspace.sizeFlink JVM进程的Metaspace
JVM开销jobmanager.memory.jvm-overhead.min
jobmanager.memory.jvm-overhead.max
jobmanager.memory.jvm-overhead.fraction
用于其他 JVM 开销的本地内存,例如栈空间、垃圾回收空间等。
配置JVM堆内存

配置总内存中所述,配置 JobManager 内存的方式是明确指定 JVM 堆内存的大小(jobmanager.memory.heap.size)。 通过这种方式,用户可以更好地掌控用于以下用途的 JVM 堆内存大小。

  • Flink 框架
  • 在作业提交时(例如一些特殊的批处理 Source)及 Checkpoint 完成的回调函数中执行的用户代码

Flink 需要多少 JVM 堆内存,很大程度上取决于运行的作业数量、作业的结构及上述用户代码的需求。

提示 如果已经明确设置了 JVM 堆内存,建议不要再设置进程总内存Flink 总内存,否则可能会造成内存配置冲突。

在启动 JobManager 进程时,Flink 启动脚本及客户端通过设置 JVM 参数 -Xms-Xmx 来管理 JVM 堆空间的大小。 请参考 JVM 参数

配置堆外内存

堆外内存包括 JVM 直接内存本地内存。 可以通过配置参数 jobmanager.memory.enable-jvm-direct-memory-limit 设置是否启用 JVM 直接内存限制。 如果该配置项设置为 true,Flink 会根据配置的堆外内存大小设置 JVM 参数 -XX:MaxDirectMemorySize。 请参考 JVM 参数

可以通过配置参数 jobmanager.memory.off-heap.size设置堆外内存的大小。 如果遇到 JobManager 进程抛出 “OutOfMemoryError: Direct buffer memory” 的异常,可以尝试调大这项配置。 请参考常见问题

以下情况可能用到堆外内存:

  • Flink 框架依赖(例如 Akka 的网络通信)
  • 在作业提交时(例如一些特殊的批处理 Source)及 Checkpoint 完成的回调函数中执行的用户代码

提示 如果同时配置了 Flink 总内存JVM 堆内存,且没有配置堆外内存,那么堆外内存的大小将会是 Flink 总内存减去JVM 堆内存。 这种情况下,堆外内存的默认大小将不会生效。

本地执行

如果你是在本地运行 Flink(例如在 IDE 中)而非创建一个集群,那么 JobManager 的内存配置将不会生效。

内存调优

独立部署模式(Standalone Deployment)下的内存配置

独立部署模式下,我们通常更关注 Flink 应用本身使用的内存大小。 建议配置 Flink 总内存(taskmanager.memory.flink.size 或者 jobmanager.memory.flink.size)或其组成部分。 此外,如果出现 Metaspace 不足的问题,可以调整 JVM Metaspace 的大小。

这种情况下通常无需配置进程总内存,因为不管是 Flink 还是部署环境都不会对 JVM 开销 进行限制,它只与机器的物理资源相关。

容器(Container)的内存配置

在容器化部署模式(Containerized Deployment)下(Kubernetes、Yarn 或 Mesos),建议配置进程总内存(taskmanager.memory.process.size或者 jobmanager.memory.process.size)。 该配置参数用于指定分配给 Flink JVM 进程的总内存,也就是需要申请的容器大小。

提示 如果配置了 Flink 总内存,Flink 会自动加上 JVM 相关的内存部分,根据推算出的进程总内存大小申请容器。

注意: 如果 Flink 或者用户代码分配超过容器大小的非托管的堆外(本地)内存,部署环境可能会杀掉超用内存的容器,造成作业执行失败。

State Backend 的内存配置

本章节内容仅与 TaskManager 相关。

在部署 Flink 流处理应用时,可以根据 State Backend的类型对集群的配置进行优化。

Heap State Backend

执行无状态作业或者使用 Heap State Backend(MemoryStateBackend 或 FsStateBackend)时,建议将托管内存设置为 0。 这样能够最大化分配给 JVM 上用户代码的内存。

RocksDB State Backend

RocksDBStateBackend使用本地内存。 默认情况下,RocksDB 会限制其内存用量不超过用户配置的托管内存。 因此,使用这种方式存储状态时,配置足够多的托管内存是十分重要的。 如果你关闭了 RocksDB 的内存控制,那么在容器化部署模式下如果 RocksDB 分配的内存超出了申请容器的大小(进程总内存),可能会造成 TaskExecutor 被部署环境杀掉。 请同时参考如何调整 RocksDB 内存以及 state.backend.rocksdb.memory.managed。

SortMerge数据Shuffle内存配置

对于SortMerge数据Shuffle,每个ResultPartition需要的网络缓冲区(Buffer)数目是由taskmanager.network.sort- shuffle.min-buffers这个配置决定的。它的 默认值是64,是比较小的。虽然64个网络Buffer已经可以支持任意规模的并发,但性能可能不是最好的。对于大并发的作业,通 过增大这个配置值,可以提高落盘数据的压缩率并且减少网络小包的数量,从而有利于提高Shuffle性能。为了增大这个配置值, 你可能需要通过调整taskmanager.memory.network.fraction, taskmanager.memory.network.min和taskmanager.memory .network.max这三个参数来增大总的网络内存大小从而避免出现 insufficient number of network buffers错误。

除了网络内存,SortMerge数据Shuffle还需要使用一些JVM Direct Memory来进行Shuffle数据的写出与读取。所以,为了使 用SortMerge数据Shuffle你可能还需要通过增大这个配置值taskmanager.memory.task.off-heap.size来为其来预留一些JVM Direct Memory。如果在你开启 SortMerge数据Shuffle之后出现了Direct Memory OOM的错误,你只需要继续加大上面的配置值来预留更多的Direct Memory 直到不再发生Direct Memory OOM的错误为止。

常见问题

IllegalConfigurationException

如果遇到从 TaskExecutorProcessUtilsJobManagerProcessUtils 抛出的 IllegalConfigurationException 异常,这通常说明您的配置参数中存在无效值(例如内存大小为负数、占比大于 1 等)或者配置冲突。 请根据异常信息,确认出错的内存部分的相关文档及配置信息

OutOfMemoryError: Java heap space

该异常说明 JVM 的堆空间过小。 可以通过增大总内存、TaskManager 的任务堆内存、JobManager 的 JVM 堆内存等方法来增大 JVM 堆空间。

提示 也可以增大 TaskManager 的框架堆内存。 这是一个进阶配置,只有在确认是 Flink 框架自身需要更多内存时才应该去调整。

OutOfMemoryError: Direct buffer memory

该异常通常说明 JVM 的直接内存限制过小,或者存在直接内存泄漏(Direct Memory Leak)。 请确认用户代码及外部依赖中是否使用了 JVM 直接内存,以及如果使用了直接内存,是否配置了足够的内存空间。 可以通过调整堆外内存来增大直接内存限制。 有关堆外内存的配置方法,请参考 TaskManagerJobManager 以及 JVM 参数的相关文档。

OutOfMemoryError: Metaspace

该异常说明 JVM Metaspace 限制过小。 可以尝试调整 TaskManagerJobManager 的 JVM Metaspace。

IOException: Insufficient number of network buffers

该异常仅与 TaskManager 相关。

该异常通常说明网络内存过小。 可以通过调整以下配置参数增大网络内存

  • taskmanager.memory.network.min
  • taskmanager.memory.network.max
  • taskmanager.memory.network.fraction
容器(Container)内存超用

如果 Flink 容器尝试分配超过其申请大小的内存(Yarn、Mesos 或 Kubernetes),这通常说明 Flink 没有预留出足够的本地内存。 可以通过外部监控系统或者容器被部署环境杀掉时的错误信息判断是否存在容器内存超用。

对于 JobManager 进程,你还可以尝试启用 JVM 直接内存限制(jobmanager.memory.enable-jvm-direct-memory-limit),以排除 JVM 直接内存泄漏的可能性。

如果使用了 RocksDBStateBackend 且没有开启内存控制,也可以尝试增大 TaskManager 的托管内存

此外,还可以尝试增大 JVM 开销)。

bernetes),这通常说明 Flink 没有预留出足够的本地内存。 可以通过外部监控系统或者容器被部署环境杀掉时的错误信息判断是否存在容器内存超用。

对于 JobManager 进程,你还可以尝试启用 JVM 直接内存限制(jobmanager.memory.enable-jvm-direct-memory-limit),以排除 JVM 直接内存泄漏的可能性。

如果使用了 RocksDBStateBackend 且没有开启内存控制,也可以尝试增大 TaskManager 的托管内存

此外,还可以尝试增大 JVM 开销)。

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值