it-roy-ru.com

Регистрация Apache Spark в Scala

Я ищу решение, позволяющее регистрировать дополнительные данные при выполнении кода на узлах Apache Spark, которые могли бы помочь в дальнейшем расследовании некоторых проблем, которые могут возникнуть во время выполнения. Попытка использовать традиционное решение, такое как, например, com.typesafe.scalalogging.LazyLogging, не удалась, потому что экземпляр журнала нельзя сериализовать в распределенной среде, такой как Apache Spark.

Я исследовал эту проблему, и на данный момент я нашел решение использовать черту org.Apache.spark.Logging, например:

class SparkExample with Logging {
  val someRDD = ...
  someRDD.map {
    rddElement => logInfo(s"$rddElement will be processed.")
    doSomething(rddElement)
  }
}

Однако похоже, что черта Logging не является постоянным решением для Apache Spark, потому что она помечена как @DeveloperApi и в документации класса упоминается: 

Это, вероятно, будет изменено или удалено в будущих выпусках.

Мне интересно - это какое-нибудь известное решение для ведения журналов, которое я могу использовать и позволит ли мне регистрировать данные при выполнении RDD на узлах Apache Spark?

@Later Edit : Некоторые комментарии ниже предлагают использовать Log4J. Я пытался использовать Log4J, но у меня все еще возникают проблемы при использовании логгера из класса Scala (а не объекта Scala) . Вот мой полный код:

import org.Apache.log4j.Logger
import org.Apache.spark._

object Main {
 def main(args: Array[String]) {
  new LoggingTestWithRDD().doTest()
 }
}

class LoggingTestWithRDD extends Serializable {

  val log = Logger.getLogger(getClass.getName)

  def doTest(): Unit = {
   val conf = new SparkConf().setMaster("local[4]").setAppName("LogTest")
   val spark = new SparkContext(conf)

   val someRdd = spark.parallelize(List(1, 2, 3))
   someRdd.map {
     element =>
       log.info(s"$element will be processed")
       element + 1
    }
   spark.stop()
 }

}

Исключение, которое я вижу:

Исключение в потоке "main" org.Apache.spark.SparkException: задача не сериализуема -> вызвана: Java.io.NotSerializableException: org.Apache.log4j.Logger

45
Bogdan N

Вы можете использовать решение Ахила, предложенное в
https://www.mail-archive.com/[email protected]/msg29010.html . Я использовал сам, и это работает. 

Ахил дас Пн, 25 мая 2015 08:20:40 -0700
Попробуйте так:

object Holder extends Serializable {      
   @transient lazy val log = Logger.getLogger(getClass.getName)    
}


val someRdd = spark.parallelize(List(1, 2, 3)).foreach { element =>
   Holder.log.info(element)
}
40
florins

Используйте Log4j 2.x. Журнал ядра был сделан сериализуемым. Задача решена.

Обсуждение Jira: https://issues.Apache.org/jira/browse/LOG4J2-801

"org.Apache.logging.log4j" % "log4j-api" % "2.x.x"

"org.Apache.logging.log4j" % "log4j-core" % "2.x.x"

"org.Apache.logging.log4j" %% "log4j-api-scala" % "2.x.x"
3
Ryan Stack
val log = Logger.getLogger(getClass.getName),

Вы можете использовать «log» для записи логов. Также, если вам нужно изменить свойства логгера, вам нужно иметь log4j.properties в папке/conf. По умолчанию у нас будет шаблон в этом месте.

1
Venkata Karthik

Это старый пост, но я хочу предоставить свое рабочее решение, которое я только что получил после многих испытаний и которое может быть полезным для других:

Я хочу напечатать содержимое rdd внутри функции rdd.map, но получить Task Not Serializalable Error. Это мое решение этой проблемы с использованием статического объекта scala, расширяющего Java.io.Serializable:

import org.Apache.log4j.Level

object MyClass extends Serializable{

val log = org.Apache.log4j.LogManager.getLogger("name of my spark log")

log.setLevel(Level.INFO)

def main(args:Array[String])
{

rdd.map(t=>

//Using object's logger here

val log =MyClass.log

log.INFO("count"+rdd.count)
)
}

}
0
khushbu kanojia

Если вам требуется выполнить некоторый код до и после функции map, filter или другой RDD, попробуйте использовать mapPartition, где основной итератор передается явно.

Пример:

val log = ??? // this gets captured and produced serialization error
rdd.map { x =>
  log.info(x)
  x+1
}

Становится:

rdd.mapPartition { it =>
  val log = ??? // this is freshly initialized in worker nodes
  it.map { x =>
    log.info(x)
    x + 1
  }
}

Каждая базовая функция RDD всегда реализуется с помощью mapPartition.

Обязательно обращайтесь с разделителем явно и не теряйте его: смотрите параметр Scaladoc, preservesPartitioning, это очень важно для производительности.

0
ragazzojp

Вот мое решение:

Я использую SLF4j (с привязкой Log4j), В моем базовом классе каждой работы спарк у меня есть что-то вроде этого: 

import org.slf4j.LoggerFactory
val LOG = LoggerFactory.getLogger(getClass) 

Непосредственно перед тем местом, где я использую LOG в распределенном функциональном коде, я копирую ссылку на регистратор в локальную константу.

val LOG = this.LOG

Это сработало для меня!

0
Thamme Gowda