Search Engine/hadoop2008. 6. 16. 17:09
출처: http://www.jaso.co.kr/159

hadoop과 관련해서 포스팅되는 글 중 속도에 대한 이슈와 관련된 글이 몇개 눈에 띈다. 이 글의 대부분은 속도가 느리다고 말하고 있다.
hadoop은 분명히 Native로 만든 코드와 비교했을 때는 속도가 느리다. 여기서 Native로 만든 코드의 의미는 다음과 같다.

Hadoop은 분산/병렬처리를 지원하는 플랫폼이기 때문에 성능 비교를 하기 위해서는 다음과 같은 프로그램을 이용하여 성능 비교를 할 수 있다.(여기서는 grep을 대상)
 1. 하나의 머신에서 CPU 100%를 충분히 사용하도록 script를 구성한다.
    일반적으로 grep 명령은 한번에 하나의 CPU만 사용한다 따라서 CPU가 4개 또는 2개 * Dual Core인 경우에는
    동시에 4개가 실행되도록 한다.
 2. 위에서 만든 script 및 입력 파일을 전체 노드에 복사한다.
 3. 입력 파일이 Cache가 될 수 있기 때문에 아주 큰 파일(시스템의 메모리보다 큰 사이즈의 파일, 5GB 이상)을
    cat > /dev/null  해준다.
    (리눅스의 경우 파일 cache의 효과가 아주 커 기존에 cat 된 파일을 다시 cat할 경우 속도는 1/10로 줄어든다.)

이렇게 실행시킨 결과와 hadoop을 비교해 보면 속도가 눈에 띄게 느리다는 것을 알 수 있다. 1/2, 1/3 수준으로 떨어진다. 원인은 다양하게 있겠지만 혹자는 자바로 구현되었기 때문이라고 말하기도 한다. 하지만 필자의 테스트 결과 자바에서 발생하는 오버헤더는 거의 10% 미만이라고 생각한다.

Hadoop에서 grep를 처리하는 로직 중에는 자바와 상관없이 Map&Reduce 자체의 오버헤더와 성능을 저하시키는 부분이 몇군데 존재한다.

1. TextInputFormat에서 사용하고 있는 LineRecordReader에서 BufferedReader나 BufferedInputStream과 같이 한번에 여러 byte를 읽는 클래스를 사용하지 않고 한번에 하나씩 읽어 처리하고 있다. 내부적으로 FSDataInputStream에서 Buffer를 사용하고 있는데 이 부분에 대해서는 좀 더 테스트를 해야지만 검증될 것 같다.

2. Read -> map function으로 전달시 오버헤드: 이 부분에서 많은 오버헤더가 발생하는 것으로 판단된다. Linux의 grep 명령의 경우 파일에서 read와 동시에 패턴 매치를 통해 결과를 처리하지만(예상) hadoop grep의 경우 파일에서 한줄 읽은 후 이것을 다시 Text에 저장하여 map function으로 전달한다. 그리고 map function에서는 전달 받은 Text의 값에서 패턴 매치를 통해 원하는 결과값을 가져오는 구조로 되어 있다. 여기서 벌써 2 ~ 3배 정도의 오버헤더가 발생한다.

3. CPU의 활용도: Linux의 grep을 이용할 경우 CPU를 100% 활용하기 위해 동시에 4개(CPU 수)가 실행되도록 하였다. Hadoop으로 grep을 실행했을때 모든 Node가 CPU를 제대로 활용하고 있는지 확인해보면 CPU가 100% 활용되지 않는 것을 볼 수 있다. 대부분은 50% 미만으로 사용하고 있다. 이것만으로 2배 이상의 속도 차이가 발생한다.
이것의 원인은 hadoop의 경우 각 Node는 자신의 처리해야 하는 Task의 max 값을 가지고 있다. 기본은 2로 설정되어 있다.(conf 파일에서 mapred.tasktracker.tasks.maximum)
이 수치를 4로 수정해서 실행시켜도 동일한 결과가 나타난다. 필자도 이부분에서 가장 의아해 했는데 하나의 Task가 수행되는 시간이 10초 미만인 경우 이 수치를 증가 시켜도 하나의 Node에서 수행되는 Task는 많아야 2 ~ 3이다. 이유는 TaskTracker가 Task를 실행시키고 다음 Task를 요청할때까지 소요되는 시간이 수초 정도 걸린다. 따라서 이 시간안에 Task가 종료되면 다음 Task가 할당될 때까지 CPU는 놀고 있게 된다. hadoop의 grep의 경우 한 노드에서는 64M만 처리하기 때문에 대부분 10초 이내에 실행된다.


이것뿐만 아니라 Map -> Reduce로 넘어갈때 발생하는 오버헤드도 무시못한다. 이 부분에 대해서는 좀 더 연구한 다음에 올리도록 하겠다.

따라서 hadoop을 사용해서 Native로 구현했을 때보다 빠른 속도는 보장하기 어렵겠지만 적어도 70 ~ 80% 이상의 수행 성능을 보장하기 위해서는 수행되는 Job의 성격에 맞게 다양한 튜닝 및 옵션 설정을 해야 한다. Native와 비교했을 때 100%의 성능이 나오면 좋겠지만 Node에 문제가 발생했을 경우 다른 Node 에서 자동으로 재시작하게 한다든지 등과 같은 Job Management를 생각한다면 그 정도 성능이면 Good 정도는 되지 않을까 생각한다.


Posted by BAGE