查看原文
其他

【大数据哔哔集20210116】Spark Trouble Shooting

大数据真好玩 大数据真好玩 2022-09-10

点击上方蓝色字体,选择“设为星标”

回复”资源“获取更多惊喜

Spark Troubleshooting(问题定位)

故障排除一:控制 reduce 端缓冲大小以避免 OOM

在 Shuffle 过程,reduce 端 task 并不是等到 map 端 task 将其数据全部写入磁盘后再去拉取,而是 map 端写一点数据,reduce 端 task 就会拉取一小部分数据,然后立即进行后面的聚合、算子函数的使用等操作。reduce 端 task 能够拉取多少数据,由 reduce 拉取数据的缓冲区 buffer 来决定,因为拉取过来的数据都是先放在 buffer 中,然后再进行后续的处理,buffer 的默认大小为 48MB。reduce 端 task 会一边拉取一边计算,不一定每次都会拉满 48MB 的数据,可能大多数时候拉取一部分数据就处理掉了。虽然说增大 reduce 端缓冲区大小可以减少拉取次数,提升 Shuffle 性能,但是有时 map 端的数据量非常大,写出的速度非常快,此时 reduce 端的所有 task 在拉取的时候,有可能全部达到自己缓冲的最大极限值,即 48MB,此时,再加上 reduce 端执行的聚合函数的代码,可能会创建大量的对象,这可难会导致内存溢出,即 OOM。如果一旦出现 reduce 端内存溢出的问题,我们可以考虑减小 reduce 端拉取数据缓冲区的大小,例如减少为 12MB。在实际生产环境中是出现过这种问题的,这是典型的以性能换执行的原理。reduce 端拉取数据的缓冲区减小,不容易导致 OOM,但是相应的,reudce 端的拉取次数增加,造成更多的网络传输开销,造成性能的下降。注意,要保证任务能够运行,再考虑性能的优化。

故障排除二:JVM GC 导致的 shuffle 文件拉取失败

在 Spark 作业中,有时会出现 shuffle file not found 的错误,这是非常常见的一个报错,有时出现这种错误以后,选择重新执行一遍,就不再报出这种错误。出现上述问题可能的原因是 Shuffle 操作中,后面 stage 的 task 想要去上一个 stage 的 task 所在的 Executor 拉取数据,结果对方正在执行 GC,执行 GC 会导致 Executor 内所有的工作现场全部停止,比如 BlockManager、基于 netty 的网络通信等,这就会导致后面的 task 拉取数据拉取了半天都没有拉取到,就会报出 shuffle file not found 的错误,而第二次再次执行就不会再出现这种错误。可以通过调整 reduce 端拉取数据重试次数和 reduce 端拉取数据时间间隔这两个参数来对 Shuffle 性能进行调整,增大参数值,使得 reduce 端拉取数据的重试次数增加,并且每次失败后等待的时间间隔加长。
val conf = new SparkConf().set("spark.shuffle.io.maxRetries", "60").set("spark.shuffle.io.retryWait", "60s")

故障排除三:解决各种序列化导致的报错

当 Spark 作业在运行过程中报错,而且报错信息中含有 Serializable 等类似词汇,那么可能是序列化问题导致的报错。序列化问题要注意以下三点:
  • 作为 RDD 的元素类型的自定义类,必须是可以序列化的;

  • 算子函数里可以使用的外部的自定义变量,必须是可以序列化的;

  • 不可以在 RDD 的元素类型、算子函数里使用第三方的不支持序列化的类型,例如 Connection。

故障排除四:解决算子函数返回 NULL 导致的问题

在一些算子函数里,需要我们有一个返回值,但是在一些情况下我们不希望有返回值,此时我们如果直接返回 NULL,会报错,例如 Scala.Math(NULL)异常。如果你遇到某些情况,不希望有返回值,那么可以通过下述方式解决:
  • 返回特殊值,不返回 NULL,例如“-1”;

  • 在通过算子获取到了一个 RDD 之后,可以对这个 RDD 执行 filter 操作,进行数据过滤,将数值为-1 的数据给过滤掉;

  • 在使用完 filter 算子后,继续调用 coalesce 算子进行优化。

故障排除五:解决 YARN-CLIENT 模式导致的网卡流量激增问题

YARN-client 模式的运行原理如下图所示:在这里插入图片描述 图 4-1 YARN-client 模式运行原理

在 YARN-client 模式下,Driver 启动在本地机器上,而 Driver 负责所有的任务调度,需要与 YARN 集群上的多个 Executor 进行频繁的通信。假设有 100 个 Executor, 1000 个 task,那么每个 Executor 分配到 10 个 task,之后,Driver 要频繁地跟 Executor 上运行的 1000 个 task 进行通信,通信数据非常多,并且通信品类特别高。这就导致有可能在 Spark 任务运行过程中,由于频繁大量的网络通讯,本地机器的网卡流量会激增。注意,YARN-client 模式只会在测试环境中使用,而之所以使用 YARN-client 模式,是由于可以看到详细全面的 log 信息,通过查看 log,可以锁定程序中存在的问题,避免在生产环境下发生故障。在生产环境下,使用的一定是 YARN-cluster 模式。在 YARN-cluster 模式下,就不会造成本地机器网卡流量激增问题,如果 YARN-cluster 模式下存在网络通信的问题,需要运维团队进行解决。

故障排除六:解决 YARN-CLUSTER 模式的 JVM 栈内存溢出无法执行问题

YARN-cluster 模式的运行原理如下图所示:在这里插入图片描述YARN-client 模式运行原理:

当 Spark 作业中包含 SparkSQL 的内容时,可能会碰到 YARN-client 模式下可以运行,但是 YARN-cluster 模式下无法提交运行(报出 OOM 错误)的情况。YARN-client 模式下,Driver 是运行在本地机器上的,Spark 使用的 JVM 的 PermGen 的配置,是本地机器上的 spark-class 文件,JVM 永久代的大小是 128MB,这个是没有问题的,但是在 YARN-cluster 模式下,Driver 运行在 YARN 集群的某个节点上,使用的是没有经过配置的默认设置,PermGen 永久代大小为 82MB。SparkSQL 的内部要进行很复杂的 SQL 的语义解析、语法树转换等等,非常复杂,如果 sql 语句本身就非常复杂,那么很有可能会导致性能的损耗和内存的占用,特别是对 PermGen 的占用会比较大。所以,此时如果 PermGen 的占用好过了 82MB,但是又小于 128MB,就会出现 YARN-client 模式下可以运行,YARN-cluster 模式下无法运行的情况。解决上述问题的方法时增加 PermGen 的容量,需要在 spark-submit 脚本中对相关参数进行设置,设置方法如代码:
--conf spark.driver.extraJavaOptions="-XX:PermSize=128M -XX:MaxPermSize=256M"
通过上述方法就设置了 Driver 永久代的大小,默认为 128MB,最大 256MB,这样就可以避免上面所说的问题。

故障排除七:解决 SparkSQL 导致的 JVM 栈内存溢出

当 SparkSQL 的 sql 语句有成百上千的 or 关键字时,就可能会出现 Driver 端的 JVM 栈内存溢出。JVM 栈内存溢出基本上就是由于调用的方法层级过多,产生了大量的,非常深的,超出了 JVM 栈深度限制的递归。(我们猜测 SparkSQL 有大量 or 语句的时候,在解析 SQL 时,例如转换为语法树或者进行执行计划的生成的时候,对于 or 的处理是递归,or 非常多时,会发生大量的递归)此时,建议将一条 sql 语句拆分为多条 sql 语句来执行,每条 sql 语句尽量保证 100 个以内的子句。根据实际的生产环境试验,一条 sql 语句的 or 关键字控制在 100 个以内,通常不会导致 JVM 栈内存溢出。

故障排除八:持久化与 checkpoint 的使用

Spark 持久化在大部分情况下是没有问题的,但是有时数据可能会丢失,如果数据一旦丢失,就需要对丢失的数据重新进行计算,计算完后再缓存和使用,为了避免数据的丢失,可以选择对这个 RDD 进行 checkpoint,也就是将数据持久化一份到容错的文件系统上(比如 HDFS)。一个 RDD 缓存并 checkpoint 后,如果一旦发现缓存丢失,就会优先查看 checkpoint 数据存不存在,如果有,就会使用 checkpoint 数据,而不用重新计算。也即是说,checkpoint 可以视为 cache 的保障机制,如果 cache 失败,就使用 checkpoint 的数据。使用 checkpoint 的优点在于提高了 Spark 作业的可靠性,一旦缓存出现问题,不需要重新计算数据,缺点在于,checkpoint 时需要将数据写入 HDFS 等文件系统,对性能的消耗较大。

【大数据哔哔集20210115】Spark算子调优五大策略

【大数据哔哔集20210113】Hive的动态分区和静态分区

【大数据哔哔集20210112】Sorry,Hbase的LSM Tree真的可以为所欲为!

【大数据哔哔集20210111】HDFS中的常用压缩算法及区别

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存