当我们写sql实现数据需求的时候,得多提醒自己,sql里的每个字段,
不管是聚合、还是join;
不管它们占的空间有多大;
不管它们是int类型的,还是一个大json串;
不管实现整个聚合的计算用的是HashAgg 、是ObjectHashAgg 或者是SortAgg;
不管实现整个JOIN的计算用的是SortMergeJoin 、是ShuffleHashJoin 、还是BroadcastHashJoin...
sql中涉及到的数据,都是要在内存里走一趟的,所以对内存的理解是一个非常重要的事情,理解的越透彻,我们在解决实际问题时,就会越清晰。
之前总是在学习sparksql的源码,接下来,打算从内存的角度,做一系列的总结,加深对spark的理解,毕竟未来几年,还是要继续和spark打交道。
内存系列会涉及到Executor整体内存的构成、我们平时常用的窗口函数、聚合函数、JOIN等,内容大概如下:
-
Spark on YARN Executor整体内存理解及Trouble Shooting
-
窗口函数内存使用理解,年前貌似写过一篇 窗口函数为什么更容易出现性能问题?——一个优化案例
-
聚合函数内存使用理解
-
JOIN内存使用理解
那下面就开始吧
1、Executor内存构成
从代码里看到,Executor内存组成如果下图:
第一层,整个Executor是YARN的一个container,而
单个container可申请的最大内存受到yarn.scheduler.maximum-allocation-mb参数限制,所以Executor的总内存受到yarn.scheduler.maximum-allocation-mb参数控制
Executor中的内存分为两个部分,一部分被JVM管理,我们标记为JVM(堆内);另一部分不被JVM管理,我们标记为OUT OF JVM(堆外)
先说OUT OF JVM吧~
spark有这么多种堆外的参数,一开始,我也疑惑,它们的区别是什么?各自的作用又是啥?该怎么理解呢?
1.1 【堆外】OUT OF JVM
按上图,从右往左
1.1.1 【基本不操作】spark.memory.offHeap.size
Spark 1.6 开始引入了Off-heap memory(SPARK-11389)。这种模式不在 JVM 内申请内存,而是调用 Java 的 unsafe 相关 API 进行诸如 C 语言里面的 malloc() 直接向操作系统申请内存,由于这种方式不经过 JVM 内存管理,所以可以避免频繁的 GC,这种内存申请的缺点是必须自己编写内存申请和释放的逻辑。
从代码上来看,引入这块,主要是为了支持Tungsten项目,Tungsten项目致力于提升Spark程序对内存和CPU的利用率,使性能达到硬件的极限。
Tungsten项目主要包括:
-
Memory Management and B