Spark问题排查思路
- 历史任务报错的常见原因
- 集群变更。例如JAR包版本冲突,环境改动,部分task集中在变更的节点导致重试次数超限,变更时间过长超过任务容错时间等。前两者需要追查异常原因,后两者一般可通过重跑解决
- 数据异常。例如数据倾斜、数据量激增、脏数据等
- 资源紧张,包括队列资源紧张(结合Yarn队列资源监控),和节点资源紧张(节点CPU、io、内存等)。后者常见于Spark Shuffle异常和task启动异常
- 集群bug,包括Spark和上下游组件等可能出现的bug,常表现为任务卡住,需结合task堆栈信息排查
- 新任务问题主要集中在用户的使用不当和环境匹配上,常见的包括
- 没有显示调用stop()方法结束(SparkSession.stop() 或 SparkContext.stop()),导致任务挂起
- 调用System.exit()方法退出,导致Spark无法执行正常的清退逻辑,状态异常
- JAR包版本冲突。常见于用户同集群环境共同依赖的jar包版本不一致,如protobuf,commons等包。这种情况可以考虑通过参数优先加载用户jar包——spark.driver.userClassPathFirst=true,spark.executor.userClassPathFirst=true
- 参数配置不合理。例如开发测试环境和生产环境的数据量不是一个级别,因此有些可以在开发测试环境使用的配置参数无法适用于生产环境
- Spark版本不一致,例如用户使用了更高版本的特性(常见于AI团队)
常见问题
内存问题
现象
driver/executor日志中出现java.lang.OutOfMemoryError或者driver日志中出现executor xxx Lost, exit code 137/143
解决方法
- 增加driver/executor 内存
- 调整shuffle分区数量 rdd对应
spark.default.parallelism,sql/dataframe操作对应spark.sql.shuffle.partitions这两个值默认为200 - 有的SQL任务会使用mapjoin/broadcastjoin等hint,由于原始表的数据很大,会出现即使driver增加很多内存,但是driver依然OOM,这个时候需要去掉mapjoin/broadcastjoin等hint
- SQL任务存在In子查询,例如insert into table xxx select * from yyy where id in( select id from zzz),3.2.0里面这种语句会走动态分区裁剪,类似broadcast导致driver OOM,这个时候要禁止动态分区裁剪
spark.sql.optimizer.dynamicPartitionPruning.enabled=false
网络超时
现象
常见以下报错
- failed to fetch shuffle partition xxxx ,connection closed,该问题是因为execcutor长时间没有接收到ESS发送到的数据导致的
- heartbeat timeout,executor向driver发送心跳信息,由于网络原因导致driver无法接收到heartbeat,有可能executor会被认为Lost
- register shuffle xxxx timeout,该问题是由于shuffletask需要将任务注册到ESS,这个动作有超时时间
解决方法
对应以上的序列号
- 可以调整网络的超时时间
spark.network.timeout=600s(默认120s) 可以调整心跳发送间隔spark.executor.heartbeatInterval=60s(默认10s),以及调整spark.network.timeout=600s- 该问题可以增加注册超时时间spark.shuffle.registration.timeout=30000
(默认5000)
任务卡住或者执行的太慢
现象
- 任务层面 scan表的时候split太多(几万十几万)会导致task频繁的分配、注册、启动的时间的等待
- join类型的选择
- 用户代码导致
- 用户的函数使用system.out输出可能会导致任务很慢
- Spark bug导致
解决方法
对应以上的序列号
- 该问题以有两点,SQL任务scan表的方式,可以通过SparkUI界面的DAG看出,如果是filesourcescan,那么可以调整spark.sql.files.maxPartitionBytes=268435456(默认256M);如果是hivetablescan,如果小文件太多的话,在spark里面会一个split一个文件,这个太多的scan task也会导致任务变慢,现在可以配置spark.sql.hiveCombine=true,然后调整spark.hadoop.mapreduce.combinesplit.size=67108864(默认64M),参考:https://blog.youkuaiyun.com/Samooyou/article/details/131601269?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22131601269%22%2C%22source%22%3A%22Samooyou%22%7D
- join类型当前在SQL任务中如果没有添加关于join的hint的话,默认一般会选择sortmergejoin,如果有的表太小还会出现broadcastjoin,当时sortmergejoin比较慢,这个时候可以选择hashjoin,hashjion可以通过配置spark.sql.join.preferSortMergeJoin=false,该参数join类型不在倾向于是使用sortmergejion
spark.sql.adaptive.maxShuffledHashJoinLocalMapThreshold=134217728(128M),join分区的数据量限制,因为要吧数据放到内存,所以要加上限制
spark.sql.adaptive.advisoryPartitionSizeInBytes=67108864(64M),该参数要小于spark.sql.adaptive.maxShuffledHashJoinLocalMapThreshold - 查看task的堆栈,判断执行的代码一直运行用户的代码,可判定是用户代码问题,需要结合代码调整(最近一例:用户将一个array 作为broadcast,后面在map算子中调用这个broadcast 判断array是否包含对应的值,由于array.contains是通过iterator一条一条的迭代,所以效率非常低,后续将array修改为map)
- 该问题让用户注释掉输出代码
- 如果代码卡在spark的代码,那应该是spark的问题,移交给spark负责人处理
类加载冲突
现象
任务中,jar包中是存在依赖的,但是依然出现NoClassFoundException或者NoSuchMethodExeption等问题
解决方法
有两个参数可以调整driver/executor的类加载顺序
spark.driver.userClassPathFirst=true 该参数仅在cluster模式下才能正常使用
spark.executor.userClassPathFirst=true
ESS何时关闭
上述提到的shuffle timeout, register timout都是因为ESS繁忙或者网络问题引起的,有些情况下ESS关闭是可以避免这些问题的,ESS关闭后
使用的就是当前Spark任务内嵌的shuffle服务,由于是一对一的服务,所以timeout是不容易出现的,那么什么时候关闭呢。
非SQL任务,并且关闭了动态分配,配置为固定的executor,这个时候是可以关闭ESS的,通过spark.shuffle.service.enabled=false
来关闭ESS,但是任务内部的shuffle服务的线程数默认是executor cores的个数,可能会引起性能的下降,所以同时需要提升该参数
spark.shuffle.io.serverThreads=8
PySpark问题
PySpark出现比较多的是使用的问题,可以参考pyspark脚手架
3万+



被折叠的 条评论
为什么被折叠?



