spark异常处理


spark 异常处理
类java
scala可以写成类似java的异常处理模式,如果是读取本地文件,
import java.io.FileReaderimport
java.io.FileNotFoundException
import java.io.IOException
object Demo {
def main(args: Array[String]) {
try {
val f = new FileReader("input.txt")
} catch {
case ex: FileNotFoundException =>{
println("Missing file exception")
} case ex: IOException => {
println("IO Exception") } } }}

简单的 判断文件是否存在
val sc: SparkContext = eachRdd.sparkContext
val hadoopConf: Configuration = sc.hadoopConfiguration
val fs: FileSystem = org.apache.hadoop.fs.FileSystem.get(hadoopConf)
// 这里是否不需要collect?
val lines: Array[(String, FtpMap)] = oiddRdd.collect()
// 文件名流转化为文件数据流
lines.foreach {
eachFileJson: (String, FtpMap) => {
  val topic: String = eachFileJson._1
  printLog.info("topic: " + topic)
  val fileJson = eachFileJson._2
  val filePath = fileJson.file_path
  val fileExists: Boolean = try {
    fs.exists(new org.apache.hadoop.fs.Path(filePath))
  } catch {
    case e: Exception => {
      printLog.error("Exception: filePath:" + filePath + " e:" + e)
      false
    }
  }
  if (fileExists) {
    val lines: RDD[String] = sc.textFile(filePath)
  }
}


Try和两个子类 Success[T] 和Failture[T]
但是如果是spark代码,读hdfs时是lazy模式,所以即使使用try-catch运行时一旦某行格式错误也会报错:
尤其针对读取 hdfs文件时报错 Caused by: java.lang.ArrayIndexOutOfBoundsException
重要方法是将string在 split的时候 Try 或的 success或failure 类型。
val tokens = lines.flatMap(_ split " ")
   .map (s => Try(s(10)))
得到Try的子类Success或者Failure,如果计算成功,返回Success的实例,如果抛出异常,返回Failure并携带相关信息
import scala.util.{Try, Success, Failure}
def divideBy(x: Int, y: Int): Try[Int] = {     //该步骤获得Success[Int] 或Failure[Int]
  Try(x / y)
}
println(divideBy(1, 1).getOrElse(0)) // 1    //该步骤重新获取Try[T]中的T类型
println(divideBy(1, 0).getOrElse(0)) //0
详细的Option,Either和Try数据处理参考: http://blog.youkuaiyun.com/jasonding1354/article/details/46822417
### Spark 常见异常场景及解决方案 #### 1. 数据倾斜(Data Skew) 数据倾斜是Spark中最常见的性能问题之一,表现为某些任务处理的数据量远大于其他任务,导致作业执行效率下降。数据倾斜通常发生在Shuffle操作中,如`groupByKey`、`reduceByKey`、`join`等操作。 - **现象**:部分任务执行时间远超其他任务;Shuffle读写量异常大;Executor内存溢出(OOM)。 - **解决方案**: - **聚合元数据**:在执行Shuffle操作前,先对数据进行预聚合,减少Shuffle数据量[^3]。 - **使用Salting技术**:对倾斜的key进行加盐处理,将一个key拆分为多个逻辑key,从而分散数据分布[^2]。 - **优化Shuffle操作**:避免不必要的Shuffle操作,如使用`map`替代`groupByKey`+`map`的方式[^4]。 - **调整分区策略**:使用`repartition`或`coalesce`重新分配数据分区,使数据更均匀分布[^2]。 #### 2. 内存溢出(Out of Memory, OOM) 内存溢出是Spark作业中常见的错误之一,通常表现为Executor或Driver端的内存不足。 - **现象**:Executor报错“ExecutorLostFailure”;Driver端出现“OutOfMemoryError”。 - **解决方案**: - **增加Executor内存**:通过`spark.executor.memory`参数增加Executor的堆内存。 - **调整GC策略**:选择合适的垃圾回收器(如G1GC)并优化GC参数。 - **减少任务并行度**:降低`spark.sql.shuffle.partitions`的值,减少单个任务处理的数据量。 - **优化数据结构**:使用更高效的数据结构(如使用`DataFrame`替代`RDD`)。 #### 3. 任务执行失败(Task Failure) 任务执行失败可能由多种原因引起,如代码逻辑错误、资源不足、数据质量问题等。 - **现象**:任务在执行过程中抛出异常;任务重试多次后失败。 - **解决方案**: - **查看Spark UI**:通过Spark UI查看失败任务的详细日志,定位具体错误原因[^5]。 - **检查日志文件**:分析Executor和Driver的日志,查找异常堆栈信息。 - **增加重试次数**:通过`spark.task.maxFailures`参数增加任务的最大失败次数。 - **优化代码逻辑**:确保代码中没有空指针、类型转换错误等问题。 #### 4. 资源调度不足(Resource Allocation Issues) 当集群资源不足时,Spark作业可能无法获得足够的Executor或CPU资源,导致作业执行缓慢或失败。 - **现象**:作业长时间处于等待状态;Executor启动失败。 - **解决方案**: - **调整资源请求参数**:合理设置`spark.executor.instances`、`spark.executor.cores`和`spark.executor.memory`等参数。 - **使用动态资源分配**:启用`spark.dynamicAllocation.enabled`,根据作业负载动态分配Executor资源。 - **优化作业优先级**:在多用户环境中,合理设置作业的优先级,确保关键作业优先执行。 #### 5. Shuffle失败(Shuffle Fetch Failed) Shuffle失败通常发生在Shuffle阶段,由于数据传输问题或Executor丢失导致。 - **现象**:报错“ShuffleMapTask: Failed to serialize task”,“FetchFailedException”等。 - **解决方案**: - **增加Shuffle文件打开数限制**:检查文件系统(如HDFS)的配置,确保足够多的文件描述符可用。 - **调整Shuffle管理器**:使用`spark.shuffle.manager`参数选择合适的Shuffle管理器(如`sort`或`tungsten-sort`)。 - **优化Shuffle数据量**:减少Shuffle阶段的数据量,如使用`reduceByKey`替代`groupByKey`。 #### 6. 数据读写异常(Data Source Exceptions) 在读写外部数据源(如HDFS、Hive、Kafka等)时,可能出现连接失败、数据格式错误等问题。 - **现象**:读取或写入数据时报错,如“FileNotFoundException”、“ClassNotFoundException”等。 - **解决方案**: - **检查数据路径**:确保HDFS或Hive表路径正确,文件存在且可读。 - **配置依赖库**:确保Driver和Executor都包含所需的数据源依赖(如JDBC驱动、Parquet格式支持等)。 - **使用合适的格式**:确保读取的数据格式与实际存储格式一致(如JSON、CSV、Parquet等)。 --- ### 示例代码:使用Salting技术缓解数据倾斜 ```python from pyspark.sql import SparkSession import random def add_salt(key, salt_buckets=10): return (key, random.randint(0, salt_buckets - 1)) def remove_salt(salted_key): return salted_key[0] # 初始化Spark会话 spark = SparkSession.builder \ .appName("DataSkewHandling") \ .getOrCreate() # 假设原始数据为RDD[(key, value)] data = spark.sparkContext.parallelize([ ("a", 1), ("a", 2), ("a", 3), ("b", 4), ("c", 5) ]) # 添加盐值 salted_data = data.map(lambda x: ((add_salt(x[0])), x[1])) # 重新分区以分散数据 salted_data = salted_data.partitionBy(spark.sparkContext.defaultPartitioner(salted_data)) # 执行聚合操作 aggregated_data = salted_data.reduceByKey(lambda a, b: a + b) # 移除盐值 result = aggregated_data.map(lambda x: (remove_salt(x[0]), x[1])) # 输出结果 result.collect() ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值