HBase를 다루는 MapReduce 프로그램을 작성하다 보니 job이 할당되고, task가 뜨다가 org.apache.hadoop.hbase.mapreduce.TableMapper 가 NoClassDefFoundError 라는 메시지를 출력하고 task가 종료되어 버린다. 한동안 손을 놓고 있다가 오랫만에 다시 보니 이거 참 새롭다. 분명히 전에도 저런 문제가 있어서 한참 끙끙댔던 기억이 난단 말이다.
classpath 문제이다. hbase.jar 를 못찾는 것인데, HADOOP_CLASSPATH 에 정의를 해 주면 된다. 일반 java 프로그램의 library 경로 지정은 CLASSPATH 환경 변수에 한다. MapReduce의 task 프로그램이 사용하는 classpath는 HADOOP_CLASSPATH이다.
문제는 이걸 알고 있지만서도 자꾸 나중에 끙끙대게 되는 것이다. 먼저 관련 문서를 참고 하자. http://hadoop.apache.org/hbase/docs/current/api/org/apache/hadoop/hbase/mapred/package-summary.html#package_description
이걸 보면 HBase 를 다루는 MapReduce 프로그램은 hadoop/conf 디렉토리에 hbase-site.xml 파일을 넣고 hbase.jar 를 hadoop/lib 디렉토리에 복사한다. 보다 확실한 방법은 hadoop/conf/hadoop-env.sh에 HADOOP_CLASSPATH 에 hbase.jar 와 hbase/conf 디렉토리를 추가하는 것이라 나와있다. task 프로그램이 사용하는 그 외 기타 라이브러리의 경로도 여기에 추가해 주면 된다. 그런데 hadoop-env.sh 의 HADOOP_CLASSPATH 값은 실제 값이어야 한다. .bashrc 같은 파일에 환경변수 값을 설정하고 hadoop-env.sh 에서 이 값을 가져다 쓰는 식으로 하면 처음엔 Job이 잘 실행되는 것처럼 보이다가 정작 task 노드에서 task가 실행될때 task프로그램이 위처럼 class 파일을 못 찾고 종료되어 버린다.
실제 파일 값을 예로 보자.
~/.bashrc
for jar in /opt/hbase/lib/*.jar; do
lib_path=${lib_path}:${jar}
done
export CLASSPATH=”/opt/hbase/hbase-0.20.0.jar:/opt/hbase/conf:${lib_path}”
:
/opt/hadoop/conf/hadoop-env.sh
export HADOOP_CLASSPATH=$CLASSPATH
:
이렇게 설정하면 안된다.
아래와 같이 실제 값을 hadoop-env.sh에 넣도록 한다. 아마 task 프로그램이 실행되면서 hadoop-env.sh 을 실행시켜서 값을 설정하는데 이용하는 것 같은데, hadoop-env.sh 안에 #!/bin/sh 없으니까 환경 변수 설정값을 못 받는게 아닌가 하는 추측이 된다.
여튼, 아래와 같이 직접 hadoop-env.sh 안에 값을 설정하도록 하자
/opt/hadoop/conf/hadoop-env.sh
for jar in /opt/hbase/lib/*.jar; do
lib_path=${lib_path}:${jar}
done
export HADOOP_CLASSPATH=/opt/hbase/hbase.jar:/opt/hbase/conf:${lib_path}
:
확인해 보진 않았지만, hbase/conf/hbase-env.sh 안의 HBASE_CLASSPATH 도 같은 맥락으로 이해하면 되지 않을까 싶다.