스택큐힙리스트

태스크는 직렬화할 수 없습니다: 단지 클래스가 아닌 객체에 대해서만 클로저 외부에서 함수를 호출할 때 java.io.NotSerializableException 본문

카테고리 없음

태스크는 직렬화할 수 없습니다: 단지 클래스가 아닌 객체에 대해서만 클로저 외부에서 함수를 호출할 때 java.io.NotSerializableException

스택큐힙리스트 2023. 11. 29. 00:02
반응형

클로저 밖에서 함수를 호출할 때 이상한 동작을 얻습니다:

 

    • 함수가 객체 안에 있을 때는 모든 것이 작동합니다

 

    • 함수가 클래스 안에 있을 때는 다음과 같이 됩니다:

 


작업이 직렬화될 수 없음: java.io.NotSerializableException: testing

문제는 코드를 개체(object)가 아닌 클래스에 넣어야 한다는 것입니다. 이런 일이 일어나는 이유가 무엇인지 아시나요? 스칼라 객체는 직렬화되나요 (기본적으로?)?

다음은 작동하는 코드 예제입니다:

object working extends App {
    val list = List(1,2,3)
    val rddList = Spark.ctx.parallelize(list)
    // 클로저 밖에서 함수 호출
    val after = rddList.map(someFunc(_))
    def someFunc(a:Int)  = a+1
    after.collect().map(println(_))
}

다음은 작동하지 않는 예제입니다:

object NOTworking extends App {
  new testing().doIT
}
//extends Serializable을 추가해도 도움되지 않습니다.
class testing {  
  val list = List(1,2,3)  
  val rddList = Spark.ctx.parallelize(list)
  def doIT =  {
    //다시 someFunc 함수를 호출합니다.
    val after = rddList.map(someFunc(_))
    //이것은 충돌할 것입니다 (spark lazy)
    after.collect().map(println(_))
  }
  def someFunc(a:Int) = a+1
}

답변 1

import org.apache.spark.{SparkContext,SparkConf}
object Spark {
  val ctx = new SparkContext(new SparkConf().setAppName(test).setMaster(local[*]))
}
object NOTworking extends App {
  new Test().doIT
}
class Test {
  val rddList = Spark.ctx.parallelize(List(1,2,3))
  def doIT() =  {
    val after = rddList.map(someFunc)
    after.collect().foreach(println)
  }
  val someFunc = (a: Int) => a + 1
}

비슷하지만 같지는 않은 클래스 직렬화 문제는 당신에게 관심이 있을 수 있으며 사용할 수 있는 이 스파크 서밋 2013 프리젠테이션에서 읽을 수 있습니다.

추가로, rddList.map(someFunc(_))rddList.map(someFunc)로 바꿀 수 있습니다. 두 구문은 정확히 동일합니다. 일반적으로, 두 번째 구문이 더 간결하고 읽기 쉽기 때문에 선호됩니다.

편집 (2015-03-15): SPARK-5307SerializationDebugger를 도입했으며, Spark 1.3.0은 이를 처음 사용하는 버전입니다. 이는 NotSerializableException에 직렬화 경로를 추가합니다. NotSerializableException이 발생하면 디버거는 객체 그래프를 검사하여 직렬화할 수 없는 객체로의 경로를 찾고 사용자가 해당 객체를 찾을 수 있도록 정보를 구성합니다.

OP의 경우, 다음과 같이 표준 출력에 인쇄됩니다:

직렬화 스택:
    - 직렬화할 수 없는 객체 (클래스: testing, 값: testing@2dfe2f00)
    - 필드 (클래스: testing$$anonfun$1, 이름: $outer, 유형: 클래스 testing)
    - 객체 (클래스 testing$$anonfun$1, <function1>)

답변 2

태스크 직렬화 불가: 객체가 아닌 클래스에서만 클로저 밖에서 함수를 호출할 때 발생하는 java.io.NotSerializableException 오류에 대해 안내해 드리겠습니다.
자바에서 직렬화(Serialization)는 객체를 바이트 스트림으로 변환하여 저장하거나 네트워크 상에서 전송할 수 있는 기능을 제공합니다. 그러나 모든 클래스와 인스턴스가 직렬화 가능한 것은 아닙니다. 이러한 상황에서는 위와 같은 예외 오류인 java.io.NotSerializableException이 발생하게 됩니다.
클래스나 객체의 직렬화가 필요한 이유는 다양합니다. 가장 대표적인 예로는 분산 환경에서 객체를 전송하여 다른 시스템에서 사용하는 경우입니다. 객체를 바이트 스트림으로 변환하면 이러한 전송이 가능해지는데, 이때 java.io.Serializable 인터페이스를 구현함으로써 객체를 직렬화할 수 있습니다. 이 인터페이스를 구현하지 않은 클래스는 직렬화가 불가능하며, NotSerializableException 오류가 발생하게 됩니다.
하지만 이러한 오류는 클래스 내부의 인스턴스 변수가 직렬화되지 않아 발생하는 것이 아닙니다. 오히려 클래스 자체가 직렬화 가능한지 여부에 영향을 받습니다. 이는 객체의 상태를 전달하는 것이 아니라 클래스의 구조를 전달하는 개념입니다.
클로저 밖에서 함수를 호출할 때 발생하는 NotSerializableException 오류는 보통 클래스의 멤버 함수를 호출할 때 발생합니다. 이는 클래스가 직렬화되지 않아서 발생하는 것이며, 클래스를 직렬화하도록 수정해야 한다는 의미입니다. 따라서 클래스를 직렬화하려면 java.io.Serializable 인터페이스를 구현하고, 필요에 따라 직렬화 가능한 변수로 선언해야 합니다.
클래스 직렬화는 데이터의 안전한 전달과 저장을 위해 매우 중요합니다. 따라서 클래스를 설계할 때 직렬화 여부를 고려하는 것이 좋습니다. 객체의 직렬화 가능 여부를 결정하기 위해서는 클래스의 모든 멤버 변수 및 메서드를 검토하고, 필요에 따라 직렬화 가능한 변수로 선언해야 합니다. 이를 통해 에러가 발생하지 않고 데이터를 안전하게 전달할 수 있습니다.
종합하면, 자바에서 함수 호출 시 발생하는 java.io.NotSerializableException 오류는 객체가 아닌 클래스의 직렬화가 불가능할 때 발생합니다. 클래스를 직렬화하거나 인스턴스 변수를 직렬화 가능하도록 수정함으로써 이 오류를 해결할 수 있습니다. 클래스의 직렬화는 데이터 안전성을 위해 필요한 작업이므로, 클래스를 설계할 때 이러한 요소를 고려하는 것이 중요합니다.

반응형
Comments