티스토리 뷰

오늘은 유닉스 쉘 코맨드로 하둡 스트리밍(Hadoop Streaming) 사용 시 주의사항에 대해서 설명 드리겠습니다.
더 정확히 말하자면, 파이프 라인 방식으로 스트리밍을 쓸 때의 주의사항이라고 할 수 있는데요. 

구글링을 해도 이 부분에 대한 자료가 의외로 찾기 어려워서, 블로그에 정리해봤습니다. ^^;;

 

예를 들어 다음과 같이 스트리밍을 실행해봅니다. 

./bin/hadoop jar contrib/streaming/hadoop-streaming-1.0.3.jar \
       -input test_input \
       -output test_out \
       -mapper "sed '1d' | cut -f 3,4 -d , | awk 'NF'" \
       -reducer "uniq" 


이 예제는 test_input 디렉터리에 있는 파일을 매퍼의 입력 데이터로 보내서, 매퍼에서는 첫번째 라인을 날린 후, 콤마를 구분자로 3,4번째 라인을 잘라내는데, 공백 라인도 함께 제거합니다. 그리고 리듀서는 매퍼의 출력 데이터를 유니크하게 계산합니다.

 

그런데 스트리밍 코맨드를 실행하면 마지막 라인에 스트리밍 코맨드가 실패했다(Streaming Command Failed!)는 오류 메시지가 출력됩니다.

 

packageJobJar: [/home/hadoop/hadoop-data/hadoop-unjar1319608312595976203/] [] /tmp/streamjob746347024560224330.jar tmpDir=null
12/08/31 00:14:36 WARN snappy.LoadSnappy: Snappy native library is available
12/08/31 00:14:36 INFO util.NativeCodeLoader: Loaded the native-hadoop library
12/08/31 00:14:36 INFO snappy.LoadSnappy: Snappy native library loaded
12/08/31 00:14:36 INFO mapred.FileInputFormat: Total input paths to process : 22
12/08/31 00:14:36 INFO streaming.StreamJob: getLocalDirs(): [/home/hadoop/hadoop-data//mapred/local]
12/08/31 00:14:36 INFO streaming.StreamJob: Running job: job_201208301204_0036
12/08/31 00:14:36 INFO streaming.StreamJob: To kill this job, run:
12/08/31 00:14:36 INFO streaming.StreamJob: /home/hadoop/hadoop-1.0.3/libexec/../bin/hadoop job  -Dmapred.job.tracker=testserver01:9001 -kill job_201208301204_0036
12/08/31 00:14:36 INFO streaming.StreamJob: Tracking URL: http://testserver01:50030/jobdetails.jsp?jobid=job_201208301204_0036
12/08/31 00:14:37 INFO streaming.StreamJob:  map 0%  reduce 0%
12/08/31 00:15:16 INFO streaming.StreamJob:  map 100%  reduce 100%
12/08/31 00:15:16 INFO streaming.StreamJob: To kill this job, run:
12/08/31 00:15:16 INFO streaming.StreamJob: /home/hadoop/hadoop-1.0.3/libexec/../bin/hadoop job  -Dmapred.job.tracker=testserver01:9001 -kill job_201208301204_0036
12/08/31 00:15:16 INFO streaming.StreamJob: Tracking URL: http://testserver01:50030/jobdetails.jsp?jobid=job_201208301204_0036
12/08/31 00:15:16 ERROR streaming.StreamJob: Job not successful. Error: # of failed Map Tasks exceeded allowed limit. FailedCount: 1. LastFailedTask: task_201208301204_0036_m_000000
12/08/31 00:15:16 INFO streaming.StreamJob: killJob...
Streaming Command Failed! 

 

그래서 데이터 노드에 생성된 각 태스크의 로그를 확인해보니, 모든 태스크에 다음과 같은 오류 메시지가 출력되어 있었습니다.

 

 java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 4
 at org.apache.hadoop.streaming.PipeMapRed.waitOutputThreads(PipeMapRed.java:362)
 at org.apache.hadoop.streaming.PipeMapRed.mapRedFinished(PipeMapRed.java:576)
 at org.apache.hadoop.streaming.PipeMapper.close(PipeMapper.java:135)
 at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:57)
 at org.apache.hadoop.streaming.PipeMapRunner.run(PipeMapRunner.java:36)
 at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:436)
 at org.apache.hadoop.mapred.MapTask.run(MapTask.java:372)
 at org.apache.hadoop.mapred.Child$4.run(Child.java:255)
 at java.security.AccessController.doPrivileged(Native Method)
 at javax.security.auth.Subject.doAs(Subject.java:396)
 at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1121)
 at org.apache.hadoop.mapred.Child.main(Child.java:249)

 

이 오류는 바로 매퍼에 설정한 코맨드가 명령어 파이프라인 방식으로 선언되었기 때문인데요. 참고로 명령어 파이프라인은 명령어를 읽어 순차적으로 실행하는 프로세서에 적용되는 기술로, 한 번에 하나의 명령어만 실행하는 것이 아니라 하나의 명령어가 실행되는 도중에 다른 명령어 실행을 시작하는 식으로 동시에 여러 개의 명령어를 실행하는 기법이다 (출처: http://ko.wikipedia.org/wiki/%EB%AA%85%EB%A0%B9%EC%96%B4_%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8). ^^;;

 

그런데 하둡 스트리밍은  리듀서를 실행할 때 매퍼의 쓰레드가 완전히 종료되어야만 실행되게 구현되어 있습니다. 하지만 파이프라인 방식은 앞서 설명 드린 대로 동시에 명령어가 실행되어서, 리듀서의 입장에서는 매퍼가 계속 실행되어서 행이 걸린 것으로 인식해서 오류가 난 것입니다. 


그래서 하둡 스트리밍에서 매퍼나 리듀서에 명령어 파이프라인을 사용하려면, 명령어를 반드시 스크립트 파일로 작성해야 합니다. 매퍼에 설정했던 명령어를 다음과 같이 스크립트 파일로 작성합니다.

 

vi mapper.sh
sed '1d' | cut -f 3,4 -d , | awk 'NF' 

 

그리고 해당 파일을 -file 이나 -files 옵션을 사용해서 모든 매퍼와 리듀서들이 참조할 수 있게 해야 합니다. 왜냐하면 스크립트 파일은 클라이언트에만 저장되어 있기 때문에, 매퍼나 리듀서가 참조할 수 없기 때문입니다.

 

이제 다음과 같이 -file 옵션과 -mapper 옵션에 mapper.sh를 설정하고, 다시 스트리밍 코맨드를 실행하면 정상적으로 스트리밍이 수행됩니다.

 

./bin/hadoop jar contrib/streaming/hadoop-streaming-1.0.3.jar \
        -file mapper.sh \
        -input test_input \
        -output test_output \
        -mapper mapper.sh \
-reducer "uniq" 

 

 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
댓글
댓글쓰기 폼