flink内存模型

jvm中java对象模型缺陷

基于 JVM 的数据分析引擎都需要面对将大量数据存到内存中,当然也包括flink,这就不得不面对JVM内存管理存在的几个问题:
1.有效数据密度低
java对象由三部分构成,对齐填充仅起到占位符的作用,例如:一个只包含 boolean 属性的对象占用了16个字节内存:对象头占了8个,boolean 属性占了1个,对齐填充占了7个。而实际上只需要一个bit(1/8字节)就够了。
在这里插入图片描述

2.垃圾回收机制
JVM的内存回收机制,优点是开发者无需关心资源回收,但是由于自主回收是不可控的,在大数据场景下,这个缺点被放大,海量数据导致空间不足,可能出现秒级甚至分钟级的Full GC,不仅影响效率,其引起的中断可能导致心跳超时被踢出集群。(所以需要JVM参数调优提升回收效率,减少FullGC)

3.OOM问题
当执行Full GC后空间仍然不足,则抛出OOM导致JVM崩溃,影响分布式框架的健壮性和性能

4.缓存未命中问题
从 L1/L2/L3 缓存读取数据的速度比从主内存读取数据的速度快好几个量级。通过性能分析可以发现,CPU时间中的很大一部分都是浪费在等待数据从主内存过来上。如果这些数据可以从 L1/L2/L3 缓存过来,那么这些等待时间可以极大地降低。
CPU将经常访问的数据及其下一步可能访问的附近的数据搬运到缓存中,以便下次访问,但由于java对象在堆中不连续(java中,为了提高效率,是按照8byte的整数倍进行存储的,所以不连续),所以搬运的附近数据往往不是下一步计算需要的,这就是缓存未命中,导致执行效率降低。
在这里插入图片描述

flink自主管理内存来解决jvm的几个问题

所以目前,越来越多的大数据项目开始自己管理JVM内存了,像 Spark、Flink、HBase,为的就是获得像 C 一样的性能以及避免 OOM 的发生。

早期flink内存模型

在flink中,使用固定长度的内存块(默认32KB)来管理java对象(而不是将存对象在堆上),即memorySegment,它是flink中内存分配的最小单元。一个java对象序列化为二进制数据流后可能占用1个或多个memorySegment。flink给这样的内存块提供了非常高效的读写方法,部分运算可以直接操作二进制数据,不需要反序列化即可执行(它的 DBMS 风格的sort和join算法尽可能多地对这个二进制数据进行操作,以此将序列化和反序列化开销降到最低,这部分内容暂时不详述)。
在这里插入图片描述

早期时候flink还未使用堆外内存,memorySegement的都是放在堆上的,基于这样的内存管理模式可以改善jvm的部分问题:

  1. 针对有效数据密度低的问题:
    因为只存储实际数据的二进制内容,避免了对齐填充等占位符,节省了内存空间。

  2. 针对Full GC的问题:
    从GC的角度讲,数据以二进制的形式存在memorySegment中一直呆在老年代不会被GC回收,而其他的数据对象基本上是由用户代码生成的短生命周期对象,这部分内存可以看成新生代,可以被Minor GC快速回收,让对象尽量在minor GC时被回收不要进入老年代,老年代空间充足的话就可以降低发生Full GC的概率

  3. 针对OOM的问题:
    分配的内存段的数量是固定的,因此监控剩余的内存资源是非常简单的,在内存吃紧的情况下,算法(sort/join等)会高效地将一大批内存块写到磁盘,之后再读回来,防止OOM。

  4. 针对缓存未命中的问题:
    该二进制形式数据把将算法中需要操作的数据(如sort中的key)连续存储,容易被缓存到L1/L2/L3中,可以减少CPU等待的时间,获得性能的提升。

当前flink内存模型

由于早期flink仅使用堆上内存,所以仍存在一些问题:

  1. JVM堆上内存过大导致JVM启动很慢
  2. 仍然可能发生Full GC,且由于数据大量存储在堆上,所以一旦发生Full GC 可达分钟级
  3. 当task需要与其他task通信时,堆内数据传输至少需要一次拷贝,导致传输性能不高

所以后来flink引入堆外内存,对象也可以存储到堆外了:

  1. 将数据分一些给堆外,减小JVM内存,加速JVM的启动
  2. 对象存储到堆外,保证堆内空间的充裕,进一步降低Full GC的概率,减小GC压力
  3. 当task需要与外界进行数据传输时,提前将二进制数据对象存储在堆外可以实现zero-copy,提高传输效率

但引入堆外内存也有一些缺点:

  1. 分配生命周期短的对象,比起堆内内存,在堆外内存上分配开销更高。
  2. 堆外内存出错时排错更为复杂。
  3. 在flink的测试中,部分操作在堆外内存上会比堆上内存更慢。

所以flink既可以使用堆内内存又可以使用堆外内存,Flink用通过ByteBuffer.allocateDirect(numBytes)来申请堆外内存,用 sun.misc.Unsafe 来操作堆外内存。flink在选择堆内或堆外内存大小上给了用户较大的自由度。

基于以上分析,给出flink现在的内存布局:
在这里插入图片描述

可以看到,flink的内存模型中:

  • flink框架使用了堆上内存和堆外内存,不计入slot资源
  • taks执行的内存也使用了堆上和堆外内存
  • 网路缓冲内存是多个slot共享的,不隔离,放在堆外,可以实现zero-copy

一.flink框架内存

  1. 用途?flink框架本身占用的内存
  2. 内存大小?通常情况下,不建议对框架堆内存和框架堆外内存进行调整,这部分的默认值是框架测试时不调度任务空跑通过测量得到的一个数据。

二.task内存

  1. 用途?userCode和libraies
  2. 内存大小?当使用HeapStateBackend时尤其需要使用Task Heap堆上内存。
Apache Flink内存模型设计旨在优化大规模数据流处理的性能,同时提供灵活的配置选项以适应不同的应用场景和硬件环境。Flink 的内存管理包括任务管理器(TaskManager)和作业管理器(JobManager)的内存分配,并且支持与 Hadoop YARN 等资源管理系统的集成。 ### TaskManager 内存结构 Flink 的 TaskManager 是实际执行任务的工作节点,其内存结构主要由以下几个部分组成: 1. **JVM Heap**:这是 Java 虚拟机堆内存,主要用于存放用户代码、Flink 框架类以及一些临时对象。 2. **Managed Memory**:这部分内存由 Flink 显式管理,用于高效的二进制存储操作,例如排序、哈希表和缓存输入分割。它可以通过 `taskmanager.memory.managed.fraction` 配置参数来控制,默认值为 0.7,表示占 JVM Heap 的 70%。 3. **Network Buffers**:网络缓冲区用于在 TaskManager 之间传输数据。它们是预分配的直接内存块,大小由 `taskmanager.network.memory.min` 和 `taskmanager.network.memory.max` 控制。 4. **JVM Overhead**:这部分内存用于 JVM 自身开销,如线程栈、垃圾回收等,通常不被纳入 Flink 的显式内存管理中。 ```yaml # 示例配置文件 flink-conf.yaml 中的内存相关设置 taskmanager.heap.size: 4096m taskmanager.memory.managed.fraction: 0.7 taskmanager.network.memory.min: 64mb taskmanager.network.memory.max: 1gb ``` ### JobManager 内存配置 JobManager 负责协调整个 Flink 作业的执行,包括调度任务、检查点协调等。它的内存需求相对较低,但仍然需要合理配置以确保高可用性和稳定性。可以通过以下参数进行调整: - `jobmanager.heap.size`:定义 JobManager 的 JVM 堆内存大小,默认为 1024m。 - `jobmanager.memory.off-heap`:是否启用堆外内存,默认为 false。 ```yaml # 示例配置文件 flink-conf.yaml 中的 JobManager 内存设置 jobmanager.heap.size: 2048m jobmanager.memory.off-heap: false ``` ### 集群模式下的内存管理 当使用 YARN 或 Kubernetes 等资源管理系统部署 Flink 时,还需要考虑外部资源管理器对内存的影响。例如,在 YARN 上启动 Flink 会话集群时,可以指定每个容器的内存大小: ```bash # 启动共享 Flink 集群并提交任务 $ ./bin/yarn-session.sh -n 4 -jm 1024 -tm 4096 -d $ ./bin/flink run -c com.demo.florian.WordCount $DEMO_DIR/target/flink-demo-1.0-SNAPSHOT.jar ``` 其中 `-jm` 表示 JobManager 的内存(MB),`-tm` 表示 TaskManager 的内存(MB)[^1]。 此外,Flink 支持基于检查点(Checkpointing)和保存点(Savepoint)的故障恢复机制,这些功能也会占用一定的内存资源。因此,在配置内存时应预留足够的空间用于状态后端存储和检查点操作。 ### 总结 Flink内存模型具有高度可配置性,开发者可以根据具体的应用场景和硬件条件进行精细调优。理解各个内存组件的作用及其相互关系是实现高效流处理的关键。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值