Hadoop, Spark S3 사용시 Bad type on operand stack Error

Hadoop, Spark을 같이 사용하는 프로그램의 경우 S3 파일 시스템에 접근할 때 "Bad type on operand stack" 에러가 발생할 수 있습니다.  결론은 Hadoop 2.7.1과 Spark 2.0.0에서 사용하는 jets3t 버전이 달라서 발생하는 문제였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
Bad type on operand stack
Exception Details:
  Location:
    org/apache/hadoop/fs/s3native/Jets3tNativeFileSystemStore.copy(Ljava/lang/String;Ljava/lang/String;)V @152: invokevirtual
  Reason:
    Type 'org/jets3t/service/model/S3Object' (current frame, stack[4]) is not assignable to 'org/jets3t/service/model/StorageObject'
  Current Frame:
    bci: @152
    flags: { }
    locals: { 'org/apache/hadoop/fs/s3native/Jets3tNativeFileSystemStore', 'java/lang/String', 'java/lang/String', 'org/jets3t/service/model/S3Object' }
    stack: { 'org/jets3t/service/S3Service', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'org/jets3t/service/model/S3Object', integer }
  Bytecode:
    0x0000000: b200 3fb9 0065 0100 9900 36b2 003f bb00
    0x0000010: 5759 b700 5812 66b6 0059 2bb6 0059 1267
    0x0000020: b600 592c b600 5912 68b6 0059 2ab4 0021
    0x0000030: b600 3ab6 0059 b600 5ab9 0069 0200 2ab4
    0x0000040: 0010 9900 302a b400 0b2a b400 212b 0101
    0x0000050: 0101 b600 6a4e 2ab4 001a 0994 9e00 162d
    0x0000060: b600 6b2a b400 1a94 9e00 0a2a 2d2c b600
    0x0000070: 6cb1 bb00 2859 2cb7 0029 4e2d 2ab4 001d
    0x0000080: b600 2e2a b400 0b2a b400 21b6 003a 2b2a
    0x0000090: b400 21b6 003a 2d03 b600 6d57 a700 0a4e
    0x00000a0: 2a2d 2bb7 0033 b1
  Exception Handler Table:
    bci [0, 113] => handler: 159
    bci [114, 156] => handler: 159
  Stackmap Table:
    same_frame(@62)
    same_frame(@114)
    same_locals_1_stack_item_frame(@159,Object[#214])
    same_frame(@166)
java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    org/apache/hadoop/fs/s3native/Jets3tNativeFileSystemStore.copy(Ljava/lang/String;Ljava/lang/String;)V @152: invokevirtual
  Reason:
    Type 'org/jets3t/service/model/S3Object' (current frame, stack[4]) is not assignable to 'org/jets3t/service/model/StorageObject'
  Current Frame:
    bci: @152
    flags: { }
    locals: { 'org/apache/hadoop/fs/s3native/Jets3tNativeFileSystemStore', 'java/lang/String', 'java/lang/String', 'org/jets3t/service/model/S3Object' }
    stack: { 'org/jets3t/service/S3Service', 'java/lang/String', 'java/lang/String', 'java/lang/String', 'org/jets3t/service/model/S3Object', integer }
  Bytecode:
    0x0000000: b200 3fb9 0065 0100 9900 36b2 003f bb00
    0x0000010: 5759 b700 5812 66b6 0059 2bb6 0059 1267
    0x0000020: b600 592c b600 5912 68b6 0059 2ab4 0021
    0x0000030: b600 3ab6 0059 b600 5ab9 0069 0200 2ab4
    0x0000040: 0010 9900 302a b400 0b2a b400 212b 0101
    0x0000050: 0101 b600 6a4e 2ab4 001a 0994 9e00 162d
    0x0000060: b600 6b2a b400 1a94 9e00 0a2a 2d2c b600
    0x0000070: 6cb1 bb00 2859 2cb7 0029 4e2d 2ab4 001d
    0x0000080: b600 2e2a b400 0b2a b400 21b6 003a 2b2a
    0x0000090: b400 21b6 003a 2d03 b600 6d57 a700 0a4e
    0x00000a0: 2a2d 2bb7 0033 b1
  Exception Handler Table:
    bci [0, 113] => handler: 159
    bci [114, 156] => handler: 159
  Stackmap Table:
    same_frame(@62)
    same_frame(@114)
    same_locals_1_stack_item_frame(@159,Object[#214])
    same_frame(@166)
	at org.apache.hadoop.fs.s3native.NativeS3FileSystem.createDefaultStore(NativeS3FileSystem.java:342)
	at org.apache.hadoop.fs.s3native.NativeS3FileSystem.initialize(NativeS3FileSystem.java:332)
	at org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2653)
	at org.apache.hadoop.fs.FileSystem.access$200(FileSystem.java:92)
	at org.apache.hadoop.fs.FileSystem$Cache.getInternal(FileSystem.java:2687)
	at org.apache.hadoop.fs.FileSystem$Cache.get(FileSystem.java:2669)
	at org.apache.hadoop.fs.FileSystem.get(FileSystem.java:371)
	at org.apache.hadoop.fs.Path.getFileSystem(Path.java:295)

이런 에러가 발생한 환경은 다음과 같은 프로젝트 빌드 환경 및 실행 환경이었습니다.

Dependency

Hadoop MapReduce나 Spark Job을 실행하는 프로젝트를 만들때 maven을 이용하여 만들었는데 다음과 같이 Dependency 설정이 되어 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
  <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>2.7.1</version>
  </dependency>
  <dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.11</artifactId>
    <version>2.0.0</version>
  </dependency>
<dependencies>

관련 Library Copy

실행 시 필요한 라이브러리까지 모두 같이 패지킹하기 위해 maven plugin 의 copy-dependencies를 사용하여 패키지 내에 관련된 모든 라이브러리를 설치하도록 하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <version>2.4</version>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
    </execution>
  </executions>
</plugin>

CLASSPATH

Job 실행 시 CLASSPATH는 다음과 같이 설정하였습니다.

1
2
3
4
5
6
7
8
9
# My Project jar file
CLASSPATH=${MY_PROJECT_HOME}/conf
for f in ${MY_PROJECT_HOME}/*.jar; do
  CLASSPATH=${CLASSPATH}:$f;
done
# My Project lib files
CLASSPATH=${CLASSPATH}:${MY_PROJECT_HOME}/lib/*
# Hadoop lib files
CLASSPATH=${CLASSPATH}:`${HADOOP_HOME}/bin/hdfs classpath`

문제 해결

처음에는 JDK 컴파일 버전이 맞지 않아서 발생하는 문제인가 하고 여러 버전으로 컴파일 해보아도 동일한 문제가 계속 발생해서 다른 버전의 라이브러리가 존재하는 것을 의심하고 CLASSPATH를 뒤져 보았습니다.

위와 같은 실행 환경에서 copy-dependencies에 의해 dependency 있는 모든 library는 MY_PROJECT_HOME/lib 디렉토리로 복사되고 실행 시 CLASSPATH에 설정 됩니다. 그리고 "bin/hdfs classpath" 명령으로 반환되는 HADOOP의 클래스 패스도 프로그램 실생 시 CLASSPATH로 설정되었습니다.

에러 메시지에 있는 jets3t 패키지를 CLASSPATH 내에 확인해보니 MY_PROJECT_HOME/lib/lib/jets3t-0.7.1.jar 파일과 ${HADOOP_HOME}/share/hadoop/tools/lib/jets3t-0.9.0.jar 두개의 다른 버전이 존재하고 있었습니다. Hadoop이 사용하는 버전을 그대로 두고 제가 만든 프로젝트의 dependency에서 <exclusion>을 추가하여 jets3t를 제거하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependencies>
  <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>2.7.1</version>
  </dependency>
  <dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.11</artifactId>
    <version>2.0.0</version>
    <exclusions>
      <exclusion>
        <groupId>net.java.dev.jets3t</groupId>
        <artifactId>jets3t</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
<dependencies>

결론

최근 데이터 처리를 위해 하나의 프로그램에서 다양한 오픈소스를 활용하고 있습니다. 따라서 이런 문제가 발생하면 가장 먼저 라이브러리간의 버전이 맞는지 확인해보는 것이 중요한 것 같습니다.


Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.