Tuning Spark
1. 数据序列化
1.1 Java 序列化
- 优点:
- 默认设置。
- 使用场景广。无需特殊设置。
- 缺点
- 慢
1.2 Kycro 序列化
- 优点
- 快
- 压缩性高
- 缺点
- 并不是支持所有的序列化类型
- 需要手工设置
2. 内存调优
2.1 内存调优的关注点
- 对象使用的内存
- 访问对象的代价
- 垃圾回收
2.2 Java对象占用空间大的原因
- 对象头占有空间
- String 40字节的多余空间,存储长度等信息
- 集合对象包含指向下一个对象的指针
- 包装类占据更大的空间
2.3 内存调优概览
2.3.1 确定内存的消耗
- web UI 的Storage Page 中可以查看RDD占有内存的大小
- 使用SizeEstimator’s estimate 方法确定特定对象的内存大小
- SizeEstimator’s estimate 方法也可以确定传播变量在每个执行器的堆中占据的空间
2.3.2 调优数据结构
- 使用数组类型的对象,原生数据类型,而不是使用标准的Java 或者 Scala的集合类型
- 避免使用包含许多小对象和指针的结构
- 推荐使用数字类型或者枚举类型,代替String类型
- 如果内存小于32字节,把指针设置成4字节而不是8字节。使用JVM的标示,-XX:+UseCompressedOops
2.3.3序列化RDD
- 使用MEMORY_ONLY_SER序列化RDD
- 推荐使用Kryo序列化
2.3.4 垃圾回收调优
- 垃圾回收的代价和Java对象的数量成正比。
- 度量GC的影响
- -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
- 收集GC的数据,GC的频率和花费的时间。
- 高级GC调优
- JVM内存管理的基本知识
- 堆内存划分成 Young 和 Old。Young区域存储短命的对象,Old存储长命的对象。
- Young 区域划分成3部分。
- Eden
- Survivor1
- Survivor2
- GC的过程如下
- Eden满了,minor GC在Eden上进行,Eden和Survivor1上的对象搬运到Survivor2
- Survivor1 和 Survivor2交换
- 如果对象足够老,或者Survivor2 满了,对象搬运到Old
- 如果Old满了,出发full GC
- Spark中GC的调优目的
- 只有long-lived的RDD存储在Old中
- Young 的大小适合存储短命的对象
- 这将会避免full GC的发生
- Spark GC 调优有用的建议
- 通过GC的统计数据分析,是否有太多的GC
- 如果minor GC很多,major GC不多。考虑增加Eden的空间。假设Eden的空间为E,则Young的大小为-Xmn=4/3*E
- 如果Old要满了:
- 减少缓存对象的使用。降低spark.memory.fraction
- 降低Young 的大小
- 改变JVM’s NewRatio
- 使用G1。-XX:+UseG1GC。增加G1 Region Size
- 假使从HDFS读数据,估算读取数据需要的内存大小。
- 监控 改变参数之后的GC频率和耗时
- JVM内存管理的基本知识
3. 其他
3.1 并行的程度。 推荐在每个CPU核上运行2-3个任务。
3.2 Reduce Task 的内存消耗
3.3 增大并行度的程度
3.4 Boardcasting 大变量
- 超过20K的变量值得考虑优化
3.5 数据本地化
- PROCESS_LOCAL 数据和代码在同一个虚拟机
- NODE_LOCAL 数据在同一个节点。
- NO_PREF 数据能被同样的快速访问。
- RACK_LOCAL 数据在同一机架的服务器上。
- ANY 数据在网络上的某处,但是不在同一机架。