flink之内存分配与内存管理

时间:2024-03-16 22:19:32

Apache Flink 1.10对任务管理器的内存模型和Flink应用程序的配置选项进行了重大更改。这些最近引入的更改使Flink更适合于各种部署环境(例如Kubernetes,Yarn,Mesos),从而对其内存消耗进行了严格控制。本文将介绍Flink 1.10中的Flink内存模型,如何设置和管理Flink应用程序的内存消耗。

1、Flink内存模型简介

对Apache Flink的内存模型有清晰的了解,可以使开发者更有效地管理各种工作负载的资源。下图说明了Flink中的主要内存组件:
flink之内存分配与内存管理
任务管理器进程是一个JVM进程。从较高的角度看,它的内存由JVM Heap和Off-Heap内存组成。这些类型的内存由Flink直接使用,或由JVM用于其特定用途(例如,元空间等)。Flink中有两个主要的内存使用者:程序员的用户代码和框架本身占用内部数据结构,网络缓冲区等的内存。

请注意:用户代码可以直接访问所有内存类型:JVM Heap,Direct和Native memory。因此,Flink不能真正控制其分配和使用。但是,有两种类型的堆外内存供任务使用,并由Flink明确控制:

(1)托管内存(堆外)
(2)网络缓冲区

后者是JVM直接内存的一部分,分配给程序员任务之间的用户记录数据交换。

2、如何设置Flink内存

在Flink 1.10中,为了提供更好的用户体验,该框架提供了内存组件的高级和细粒度调整。在任务管理器中设置内存基本上有三种选择。

前两个(也是最简单的)替代方案是配置以下两个选项之一,以供任务管理器的JVM进程使用的总内存:
(1)总进程内存:Flink Java应用程序(包括用户代码)和JVM运行整个进程所消耗的总内存。
(2)Flink总内存:仅Flink Java应用程序消耗的内存,包括用户代码,但不包括JVM为其运行而分配的内存。

建议为standalone模式配置“ 总Flink内存”,在这种情况下,显式声明为Flink分配多少内存是一种常见做法,而外部JVM开销却很少。对于在容器化环境(例如Kubernetes,Yarn或Mesos)中部署Flink的情况,建议使用Total Process Memory(总进程内存)选项,因为它变成了所请求容器的总内存大小。容器化环境通常严格执行此内存限制。

如果您希望对JVM堆和托管内存(非堆)的大小进行更细粒度的控制,则还有另一种方法可以同时配置Task Heap和Managed Memory。这种选择可以使堆内存和任何其他内存类型之间明确分开。

与flink社区统一批处理和流处理的努力相一致,此模型在两种情况下都通用。它允许在任何工作负载中的操作员任务的用户代码与流处理方案中的堆状态后端之间共享JVM堆内存。以类似的方式,托管内存可用于批量溢出和流式传输中的RocksDB状态后端。

其余的内存组件将根据其默认值或其他已配置的参数自动进行调整。Flink还检查整体一致性。您可以在相应的文档中找到有关不同内存组件的更多信息。

3、其他组件

在配置Flink的内存时,不同内存组件的大小既可以使用相应选项的值固定,也可以使用多个选项进行调整。下面我们提供有关内存设置的更多信息。

总Flink内存的分数
此方法允许按比例细分总Flink内存,其中托管内存(如果未明确设置)和网络缓冲区可以占用其中的一部分。然后,将剩余的内存分配给任务堆(如果未明确设置)和其他固定的JVM堆和脱离堆组件。下图代表这种设置的示例:
flink之内存分配与内存管理请注意:
(1)Flink将验证派生的网络内存的大小在其最小值和最大值之间,否则Flink的启动将失败。最大和最小限制具有默认值,这些默认值可以被相应的配置选项覆盖。

(2)通常,Flink将配置的分数视为提示。在某些情况下,派生值可能与分数不匹配。例如,如果将“ 总Flink内存”和“ 任务堆”配置为固定值,则“ 托管内存”将获得一定比例,而“ 网络内存”将获得可能与该比例不完全匹配的剩余内存。

更多提示来控制容器的内存限制

堆和直接内存使用情况由JVM管理。Apache Flink或其用户应用程序中还有许多其他可能的本地内存消耗来源,这些来源不受Flink或JVM的管理。通常很难控制它们的限制,这会使调试潜在的内存泄漏变得复杂。如果Flink的进程以不受管理的方式分配过多的内存,则通常可能导致在容器化环境中杀死Task Manager容器。在这种情况下,可能很难理解哪种类型的内存消耗已超过其限制。Flink 1.10引入了一些特定的调整选项,以清楚地表示这些组件。尽管Flink不能总是强制执行严格的限制和限制,但是这里的想法是明确计划内存使用。

(1)RocksDB的状态不能变得太大。RocksDB状态后端的内存消耗是在托管内存中解决的。RocksDB默认情况下遵守其限制(仅自Flink 1.10起)。您可以增加托管内存的大小以提高RocksDB的性能,也可以减小托管内存的大小以节省资源。
(2)用户代码或其依赖项会消耗大量的堆外内存。调整“ 任务外堆”选项可以为用户代码或其任何依赖项分配其他直接或本机内存。Flink无法控制本机分配,但它设置了JVM Direct内存分配的限制。该直接内存限制是由JVM执行。
(3)JVM元空间需要额外的内存。如果遇到OutOfMemoryError: Metaspace,Flink提供了一个增加其限制的选项,并且JVM将确保不超过该限制。
(4)JVM需要更多内部内存。无法直接控制某些类型的JVM进程分配,但是Flink提供了JVM开销选项。这些选项允许声明额外的内存量,这些内存是为这些分配所预期的,并且未被其他选项覆盖。

4、结论

Flink版本(Flink 1.10)对Flink的内存配置进行了一些重大更改,从而可以比以前更好地管理应用程序内存和调试Flink。该领域的未来发展还包括在FLIP-116中为作业管理器过程采用类似的内存模型,因此请继续关注即将发布的版本中的更多新增功能。

本文翻译于flink官网