본문 바로가기
BigData/Spark & Spark Tuning

[Spark] issue 정리, java.lang.ExceptionInInitializerError 와 java.lang.IllegalStateException: SparkSession should only be created and accessed on the driver

by 스파이디웹 2024. 6. 22.
728x90

scala언어로 spark object를 만들고 jar로 빌드하여 EMR에 제출할 때 나온 에러를 정리하겠습니다.

spark관련 정리는 오랜만이네요.


1. 원인 파악

분명 다른 object와 다른점 없고, jar파일 위치 이름, class 이름까지도 경로에 명시를 잘해 줬는데도 위 제목과 같은 에러가나와서 계속 헤메고 있던 때에 리서칭을 통해서 원인을 파악할 수 있었습니다.

scala object에서 다음과 같은 에러가 나온 경우, 주로 Apache Spark에서 SparkSession드라이버 노드가 아닌 워커 노드에서 생성되거나 접근될 때 발생된다고 합니다.

→ 이는 SparkSession이 조정 목적으로 드라이버에서 관리되어야 하는 싱글톤 객체이기 때문

 

java.lang.ExceptionInInitializerError

java.lang.IllegalStateException: SparkSession should only be created and accessed on the driver

 

SparkSession이라는 힌트를 얻었고, 관련해서 여러 시도를 해보던 중에 아래와 같은 글도 확인하였습니다.

변환(map,flatMap,filter등)이나 액션(foreach,collect등) 내에서 SparkSession을 인스턴스화하거나 사용하려고 하면 이 오류가 발생 → 이러한 함수들은 워커 노드에서 실행되기 때문

 

기본적으로 spark는 아래와 같은 특징을 갖고 있습니다

  1. 드라이버 노드 vs. 워커 노드:
    • 드라이버 노드: 이 노드는 Spark 애플리케이션이 실행되는 주요 노드입니다. Spark 작업의 실행을 조정하고 SparkSession을 유지하는 역할
    • 워커 노드: 이 노드들은 실제 데이터 처리 작업을 수행합(작업 실행, 변환 실행 등)
  2. SparkSession:
    • SparkSession은 Spark와 상호작용하기 위한 통합 진입점으로, SQL, DataFrame, 스트리밍 등의 다양한 Spark 기능에 접근할 수 있게 해줍니다. 이는 한 번만 생성되어야 하며, 이 인스턴스는 드라이버 노드에 있어야 함

위의 내용들을 종합적으로 봤을 때, 내 코드가 문제가 될 만한 포인트를 찾아보니, sparksession을 object 내부에, function 외부에 정의를 해두었습니다.

그런데 같은 프로젝트의 다른 object에서도 동일하게 적용한 코드가 있는데, 걔내는 왜 에러가 안났지? 라는 의문이 들었습니다. 이 또한 위에서 힌트를 찾을 수 있었는데, rdd 레벨에서의 map과같은 함수가 문제가 됐던 것 같습니다.

 


2. 해결 방법 및 조치

해결방법은 원인을 알고 나니 의외로 간단했는데요.

object 내부 함수 외부에 정의된 SparkSession 정의를 object 내부 main함수 내부에 sparksession을 정의하는 것 이였습니다.

 

AS-IS 코드

object SparkExample {
	val spark: SparkSession.builder().appName("Spark Application").getOrCreate()


	def filterByAge() Unit = {
        ...
    }

	def main(args: Array[String]): Unit = {
		...
	}

}

TO-BE 코드

object SparkExample {

    def filterByAge(spark: SparkSession) Unit = {
        ...
      }

    def main(args: Array[String]): Unit = {
        val spark: SparkSession.builder().appName("Spark Application").getOrCreate()
        ...
    }

}


아래 TO-BE코드와 같이 변경해주니, 에러없이 잘 수행 되었습니다.

728x90

댓글