Spark 问题汇总

在大数据领域,spark 是一个比较受欢迎的大数据处理平台,但是由于数据量过大等一系列问题,造成任务执行不成功,现在总结个人在工程实践中遇到的一些个奇葩问题.

1.数据倾斜问题
现象:
1.可能会报资源不足,内存溢出
2.大部分task 均执行完,只有少数几个task始终在执行中
3.报错:Container killed on request. Exit code is 143
针对数据倾斜问题的解决见:https://blog.csdn.net/u014535908/article/details/80200924 有更加详细的解决方案

2.Kyro 序列化问题
现象:
1.报异常:

| org.apache.spark.SparkException: Kryo serialization failed: Buffer overflow. Available: 0, required: 3. To avoid this, increase spark.kryoserializer.buffer.max value. at org.apache.spark.serializer.KryoSerializerInstance.serialize(KryoSerializer.scala:315) at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:381) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)| |
报错原因:Kryo序列化溢出了,问题是因为你的结果太大了导致的,默认kryo的Buffer max是64M, 你单个task的结果大小压缩后超了64M所以导致有问题。
修改建议:
a. 增大并发数
b. 减小结果(过滤最终结果)
c. 修改提job 配置(最简单,但不建议使用的方式(临时任务可以使用,例行化任务建议上面的优化建议))

// 默认
--conf spark.kryoserializer.buffer.max=64m
--conf spark.kryoserializer.buffer=64k
// 按需增大,修改实例如下
--conf spark.kryoserializer.buffer.max=256m
--conf spark.kryoserializer.buffer=64m

注意:尽量少引入大的collect 操作
- 异常-2

2019-06-05,10:39:37,351 ERROR org.apache.spark.executor.Executor: Exception in task 4299.1 in stage 3.0 (TID 43367)
java.lang.IndexOutOfBoundsException: Index: 44, Size: 0
	at java.util.ArrayList.rangeCheck(ArrayList.java:657)
	at java.util.ArrayList.get(ArrayList.java:433)
	at com.esotericsoftware.kryo.util.MapReferenceResolver.getReadObject(MapReferenceResolver.java:60)
	at com.esotericsoftware.kryo.Kryo.readReferenceOrNull(Kryo.java:857)
	at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:811)
	at org.apache.spark.serializer.KryoDeserializationStream.readObject(KryoSerializer.scala:244)
	at org.apache.spark.serializer.DeserializationStream$$anon$1.getNext(Serializer.scala:169)
	at org.apache.spark.util.NextIterator.hasNext(NextIterator.scala:73)
	at org.apache.spark.InterruptibleIterator.hasNext(InterruptibleIterator.scala:39)
	at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:461)
	at scala.collection.Iterator$$anon$11.hasNext(Iterator.scala:408)
	at scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:461)
	at org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:193)
	at org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:63)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:96)
	at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:53)
	at org.apache.spark.scheduler.Task.run(Task.scala:100)
	at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:335)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

原因分析:
1.现象就是Kryo反序列的时侯根据读到的referenceid去referenceMap里面拿,结果Index超了,按理说如果序列化和反序列化一致的话不会出现这种情况,除非读出referenceid不对(序列化和反序列化不一致问题)
2.多核以及并发造成数据序列化和反序列化不一致
3.机器问题
- persist到机器磁盘的数据再读起来的时候出现indexOutOfBounds异常
- 直接拉shuffle数据,多个不同的机器上执行重该异常机器拉数据出现问题.
4. 操作的数据原本是压缩数据,可能解压缩之后一般会膨胀4-6倍,并且输出的结果可能因为计算比输入更大,所以单个task的结果大于默认的64M buffer大小.
解决方案:
如果是多核的原因的话,可以使用每个excutor 单核执行,其他原因还在研究

3.take, top, takeOrdered的理解
在实际工程实现中,该问题导致的坑主要是因为对于函数的具体功能不了解,见名知意的自信妄断导致.
这里主要说明一下各函数的功能和使用

  1. take
    主要针对数据根据某种排序,如果数据本身无须则根据存储的索引去前N个元素,对于排序后,取数据topN较常使用
  2. top
    主要是取数据前N个元素, 如果数据按照某一数据列排序,使用该方法无效.
  3. takeOrdered
    功能和top相似,只是获取元素按top逆序的topN个.

坑4, sort take组合使用的坑
首先描述一下问题:问题是原来有个map固定大小1w,现有一批新的数据,我们想根据某个统计指标,使用新的数据作为key替换原map中的数据key.于是乎出现以下code:

//将新旧数据join
val diff_data = diff.zipWithIndex
      .map{line =>
        val ad = line._1
        val ad_index = line._2 + old_data_size + 1
        (ad, ad_index.toString)
      }

    val old_data_set = old_map.toSet
    val increment_data_map = spark.sparkContext.makeRDD(old_data_set.union(diff_data).toSeq)
Console.err.println("run increment map ....")
	// join统计指标
      val join_data = increment_data_map.leftOuterJoin(data_static_v) 
        .map{line =>
          val ad = line._1
          val index = line._2._1
          val pv = line._2._2.getOrElse(0)
          (ad, index.toLong, pv.toLong)
        }//.toDF("ad","index","pv")
      val join_data_count = join_data.count()
      // 三元组排序 需要确定排序的正序和倒序对应, 因此这里添加f._2的排序其中f._2为全局唯一,下面逆序相同
      val sort_data_delta = join_data.sortBy(f=>(f._3, f._2)).take((join_data_count-threshold).toInt) //.take(temp_data_count - threshold)
        .map{line => line._2}
        .filter(line => line <= threshold)

      var index = -1
      val sort_data_threshold = join_data.repartition(1).sortBy(f=>(-f._3, -f._2))
        .take(threshold.toInt)
        .map{line =>
          val ad = line._1
          if (line._2 > threshold)
          {
            index += 1
            // for debug
            Console.err.println("check error: index="+index+"sort_data_delta size="+sort_data_delta.size)
            val ad_index = sort_data_delta(index)
            (ad , ad_index.toString)
          }
          else
          {
            val ad_index = line._2
            (ad , ad_index.toString)
          }
        }
        ```     

你可能感兴趣的:(计算机,云计算,Spark,数据处理)