其他
【大数据哔哔集20210116】Spark Trouble Shooting
点击上方蓝色字体,选择“设为星标”
回复”资源“获取更多惊喜
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 端拉取数据的重试次数增加,并且每次失败后等待的时间间隔加长。故障排除三:解决各种序列化导致的报错
当 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-CLUSTER 模式的 JVM 栈内存溢出无法执行问题
YARN-cluster 模式的运行原理如下图所示:在这里插入图片描述YARN-client 模式运行原理:故障排除七:解决 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 等文件系统,对性能的消耗较大。【大数据哔哔集20210113】Hive的动态分区和静态分区