Spark 调优(二):JVM 调优

Spark 由 Scala/Java 编写的,Spark 的 Driver 和 Executor 是运行在集群中的 JVM 进程,依赖 Java 内存管理和 GC。在生产环境中,通常使用几十上百甚至更大的内存,这在传统的 Java 应用中极为少见。

Spark 通过 spark.driver.extraJavaOptionsspark.executor.extraJavaOptions 可以为 Driver 和 Executor 添加额外的 JVM 标识。

GC 监控

实时监控

开启 JMX:

-Dcom.sun.management.jmxremote.port=<端口号> -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

即可以通过 JDK 自带的 GUI 工具 jconsolejstat 实时监控程序。

以使用 jstat 查看 GC 为例:

jstat -gc <进程号>@<主机名>:<端口号>  

关于 JMX 的更多信息,点击 Monitoring and Management Using JMX Technology 查看。

打印信息

输出 GC 信息到 Worker 节点的 stdout 输出:

-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

垃圾收集

JVM 使用了分代垃圾收集方式,将堆划分为不同的代,新生代(Young Generation)和老年代(Old Generation)。新生代又划分为 Eden 空间和 Survivor 空间。

JVM Heap

JVM 提供了 4 中不同的垃圾收集算法:

  • Serial 垃圾收集器
  • Throughput 垃圾收集器
  • CMS 垃圾收集器
  • G1 垃圾收集器

G1 垃圾收集器,在应用线程停顿时,使用多个线程回收新生代空间,使用后台线程回收老年代空间,从而最大程度减小停顿。适用于有足够的 CPU 资源且堆内存较大的场景。

Databricks 的博文,关于使用 G1 垃圾收集器调优 Spark:Tuning Java Garbage Collection for Apache Spark Applications

使用 G1 垃圾收集器,-XX:+UseG1GC

Executor 堆内存大,通过 -XX:G1HeapRegionSize 标识增加 G1 Region 的大小。

Tips

如果任务从 HDFS 读取数据,任务使用的内存大小可以通过从 HDFS 数据块大小估计出来。注意,解压缩之后的数据块经常增长两到三倍。所以,如果有四个任务,HDFS 块大小为 128MB,估计 Eden 大小为 4*3*128MB

内存大于 4GB 小于 32GB,-XX:+UseCompressedOops 启动指针压缩。

JVM 调优常用标识:

标识 说明
-XX:NewRatio 设置新生代与老年代之间的比率
-XX:SurvivorRatio 设置 Survivor 与 Eden 之间的比率
-Xmn 设置新生代大小
-XX:MaxGCPauseMills 设置 G1 最长停顿时间,默认 200 毫秒
-XX:ConcGCThread 设置 G1 后台扫描线程数
-XX:G1HeapRegionSize 设置 G1 Region 大小

参考