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
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值