Spark 内存管理之Tungsten
Tungsten项目概述
Tungsten号称Spark有史以来最大的改动,其致力于提升Spark程序对内存和CPU的利用率,使性能达到硬件的极限,主要工作包含以下三个方面
- Memory Management and Binary Processing: leveraging application semantics to manage memory explicitly and eliminate the overhead of JVM object model and garbage collection。
- Cache-aware computation: algorithms and data structures to exploit memory hierarchy。
- Code generation: using code generation to exploit modern compilers and CPUs。
大致的内容如下
- Memory Management and Binary Processing: off-heap管理内存,降低对象的开销和消除JVM GC带来的延时。
- Cache-aware computation: 优化存储,提升CPU L1/ L2/L3缓存命中率。
- Code generation: 优化Spark SQL的代码生成部分,提升CPU利用率。
上述第一点和内存管理相关,是本篇文章关注的重点。
为什么Tungsten关注内存和CPU
- 从硬件角度,网路带宽和磁盘读写都有大幅度提升,例如10Gbps的网络设备和SSD,使用SSD存储数据的公司在逐步增多,并且价格在可接受范围。
- 从软件角度,Spark做了许多降低网络传输和磁盘IO方面的工作,例如就近执行、序列化等。
- 此外,databricks的研究也表明CPU是主要的瓶颈,参考Spark Performance Analysis。
Spark中JVM的不足
运行在JVM之上的程序,依赖JVM管理内存及回收垃圾,但会存在两个显著问题
-
Java对象空间开销大
以UTF-8编码的字符串abcd为例,仅存储字符串信息需要4 bytes,然而使用Java的String存储则需要48 bytes,使用jol打印出String的内部占用(参考Java Object Layout(jol) ),如下OFFSET SIZE TYPE DESCRIPTION VALUE
使用jol打印出abcd占用空间大小,如下
0 12 (object header) N/A
12 4 char[] String.value N/A
16 4 int String.hash N/A
20 4 int String.hash32 N/A
Instance size: 24 bytes[email protected] footprint:
COUNT AVG SUM DESCRIPTION
1 24 24 [C
1 24 24 java.lang.String
2 48 (total) GC带来的时间开销
full gc会stop the world,增加程序耗时,甚至可能出现假死情况,并且这种情况没有日志输出,给问题排查带来一定难度。
基于以上考虑,Tungsten项目优化内存的使用,使用off-heap方式管理内存,不再依赖JVM,避免了存储的额外开销及GC的影响。
Tungsten内存管理
off-heap
off-heap是指类似C语言的方式,直接向OS申请及释放的内存。JVM提供了sun.misc.Unsafe API实现上述操作(参考Understanding sun.misc.Unsafe),Spark对应的代码如下
上图中Platform类是对sun.misc.Unsafe的简单封装,返回的内存地址和内存大小封装为MemoryBlock。
off-heap内存管理
以BytesToBytesMap为例介绍上面申请的MemoryBlock的使用。
Spark 内存管理之BytesToBytesMap
总结
介绍Tungsten中内存管理相关部分。
参考:
Project Tungsten: Bringing Apache Spark Closer to Bare Metal
Java Object Layout(jol)
Understanding sun.misc.Unsafe